diff --git a/client/src/components/NavigationConfirmPopup/index.style.ts b/client/src/components/NavigationConfirmPopup/index.style.ts
new file mode 100644
index 00000000..d8d07884
--- /dev/null
+++ b/client/src/components/NavigationConfirmPopup/index.style.ts
@@ -0,0 +1,10 @@
+import { cva } from "class-variance-authority";
+
+export const buttonStyles = cva("flex-1 py-400 rounded-1000 h-body-1-regular transition-all", {
+ variants: {
+ variant: {
+ primary: "bg-s-blue border border-s-blue text-n-white hover:bg-s-hover",
+ secondary: "bg-n-white border border-s-blue text-s-blue hover:bg-neutral-100",
+ },
+ },
+});
diff --git a/client/src/components/NavigationConfirmPopup/index.tsx b/client/src/components/NavigationConfirmPopup/index.tsx
new file mode 100644
index 00000000..1b421c44
--- /dev/null
+++ b/client/src/components/NavigationConfirmPopup/index.tsx
@@ -0,0 +1,48 @@
+import { useEffect } from "react";
+import { buttonStyles } from "./index.style";
+
+interface NavigationConfirmPopUpProps {
+ handleConfirm: () => void;
+ handleClose: () => void;
+}
+
+export default function NavigationConfirmPopUp({
+ handleConfirm,
+ handleClose,
+}: NavigationConfirmPopUpProps) {
+ useEffect(() => {
+ document.body.style.overflow = "hidden";
+
+ return () => {
+ document.body.style.overflow = "unset";
+ };
+ }, []);
+
+ return (
+
+
+
+
+ 이 페이지를 떠나면 모든 변경 사항이 저장되지 않습니다.
+
+ 페이지를 떠나시겠습니까?
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/client/src/components/PopUp/index.stories.tsx b/client/src/components/PhoneNumberPopUp/index.stories.tsx
similarity index 84%
rename from client/src/components/PopUp/index.stories.tsx
rename to client/src/components/PhoneNumberPopUp/index.stories.tsx
index 784b9690..9d81ee3e 100644
--- a/client/src/components/PopUp/index.stories.tsx
+++ b/client/src/components/PhoneNumberPopUp/index.stories.tsx
@@ -1,6 +1,6 @@
import { useState } from "react";
import type { Meta } from "@storybook/react";
-import Component, { PopUpProps } from "./index";
+import Component, { PhoneNumberPopUpProps } from "./index";
const meta = {
title: "PopUp",
@@ -15,7 +15,7 @@ const meta = {
export default meta;
-const PopUp = (args: PopUpProps) => {
+const PopUp = (args: PhoneNumberPopUpProps) => {
const [phoneNumber, setPhoneNumber] = useState(args.phoneNumber);
const handlePhoneNumberChange = (val: string) => {
@@ -32,7 +32,7 @@ const PopUp = (args: PopUpProps) => {
);
};
-export const Default = (args: PopUpProps) => (
+export const Default = (args: PhoneNumberPopUpProps) => (
<>
>
diff --git a/client/src/components/PopUp/index.tsx b/client/src/components/PhoneNumberPopUp/index.tsx
similarity index 97%
rename from client/src/components/PopUp/index.tsx
rename to client/src/components/PhoneNumberPopUp/index.tsx
index 4fbac935..849f3763 100644
--- a/client/src/components/PopUp/index.tsx
+++ b/client/src/components/PhoneNumberPopUp/index.tsx
@@ -4,19 +4,19 @@ import CTAButton from "../CTAButton";
import CheckBox from "../CheckBox";
import Input from "../Input";
-export interface PopUpProps {
+export interface PhoneNumberPopUpProps {
phoneNumber: string;
handlePhoneNumberChange: (val: string) => void;
handlePhoneNumberConfirm: (val: string) => void;
handleClose: () => void;
}
-export default function PopUp({
+export default function PhoneNumberPopUp({
phoneNumber = "",
handlePhoneNumberChange,
handlePhoneNumberConfirm,
handleClose,
-}: PopUpProps) {
+}: PhoneNumberPopUpProps) {
const [isUserInfoCheck, setIsUserInfoCheck] = useState(true);
const [isMarketingInfoCheck, setIsMarketingInfoCheck] = useState(true);
const [canConfirm, setCanConfirm] = useState(false);
diff --git a/client/src/features/Rush/Common/Headline.tsx b/client/src/features/Rush/Common/Headline.tsx
index aad6d7ab..79bdb37d 100644
--- a/client/src/features/Rush/Common/Headline.tsx
+++ b/client/src/features/Rush/Common/Headline.tsx
@@ -5,7 +5,7 @@ import CTAButton from "@/components/CTAButton";
import Scroll from "@/components/Scroll";
import { ASCEND, ASCEND_DESCEND, SCROLL_MOTION } from "@/constants/animation.ts";
import { useAuth } from "@/hooks/useAuth.ts";
-import usePopup from "@/hooks/usePopup.tsx";
+import usePhoneNumberPopUp from "@/hooks/usePhoneNumberPopup";
import useToast from "@/hooks/useToast.tsx";
import { GetTotalRushEventsResponse } from "@/types/rushApi.ts";
import { SectionKeyProps } from "@/types/sections.ts";
@@ -21,7 +21,7 @@ export function Headline({ id, handleClickScroll }: HeadlineProps) {
const { phoneNumberState, handlePhoneNumberChange, handlePhoneNumberConfirm } =
useAuth("/rush/game");
- const { handleOpenPopup, PopupComponent } = usePopup({
+ const { handleOpenPopup, PopupComponent } = usePhoneNumberPopUp({
phoneNumber: phoneNumberState,
handlePhoneNumberChange,
handlePhoneNumberConfirm,
diff --git a/client/src/features/RushGame/RushGameSections/FinalResult.tsx b/client/src/features/RushGame/RushGameSections/FinalResult.tsx
index 02893571..d0bf137f 100644
--- a/client/src/features/RushGame/RushGameSections/FinalResult.tsx
+++ b/client/src/features/RushGame/RushGameSections/FinalResult.tsx
@@ -24,18 +24,13 @@ function getWinStatus(ratio: number, oppositeRatio: number): WinStatus {
return ratio > oppositeRatio ? WIN_STATUS.WIN : WIN_STATUS.LOSE;
}
-interface FinalResultProps {
- unblockNavigation: () => void;
-}
-
-export default function FinalResult({ unblockNavigation }: FinalResultProps) {
+export default function FinalResult() {
const [cookies] = useCookies([COOKIE_KEY.ACCESS_TOKEN]);
const { cardOptions, userParticipatedStatus, userSelectedOption } = useRushGameStateContext();
const { getRushResult, resultData } = useFetchRushResult();
useEffect(() => {
getRushResult(cookies[COOKIE_KEY.ACCESS_TOKEN]);
- unblockNavigation();
}, []);
const isWinner = resultData?.isWinner;
diff --git a/client/src/features/RushGame/RushGameSections/SelectedCard.tsx b/client/src/features/RushGame/RushGameSections/SelectedCard.tsx
index 161da784..29029066 100644
--- a/client/src/features/RushGame/RushGameSections/SelectedCard.tsx
+++ b/client/src/features/RushGame/RushGameSections/SelectedCard.tsx
@@ -52,11 +52,7 @@ function SelectedCardCurrentRatio({ onClick }: SelectedCardDetailsProps) {
);
}
-interface SelectedCardProps {
- unblockNavigation: () => void;
-}
-
-export default function SelectedCard({ unblockNavigation }: SelectedCardProps) {
+export default function SelectedCard() {
const { toggleContents, toggle } = useToggleContents({ useDuration: false });
const fetchRushBalance = useFetchRushBalance();
@@ -67,7 +63,6 @@ export default function SelectedCard({ unblockNavigation }: SelectedCardProps) {
useEffect(() => {
fetchRushBalance();
- unblockNavigation();
}, []);
return (
diff --git a/client/src/hooks/useBlockNavigation.ts b/client/src/hooks/useBlockNavigation.ts
index e43d4c0c..2d9acbef 100644
--- a/client/src/hooks/useBlockNavigation.ts
+++ b/client/src/hooks/useBlockNavigation.ts
@@ -1,16 +1,29 @@
import { useEffect, useState } from "react";
-import { unstable_usePrompt, useLocation } from "react-router-dom";
+import { useBlocker, useLocation } from "react-router-dom";
-export function useBlockNavigation(message: string) {
+export function useBlockNavigation() {
const location = useLocation();
const [isBlocking, setIsBlocking] = useState(false);
- unstable_usePrompt({ when: isBlocking, message });
+ const blocker = useBlocker(isBlocking);
+ const isBlockedNavigation = blocker.state === "blocked";
const unblockNavigation = () => {
setIsBlocking(false);
};
+ const cancelNavigation = () => {
+ if (blocker.state === "blocked") {
+ blocker.reset();
+ }
+ };
+
+ const proceedNavigation = () => {
+ if (blocker.state === "blocked") {
+ blocker.proceed();
+ }
+ };
+
const handleBeforeUnload = (e: BeforeUnloadEvent) => {
if (isBlocking) {
e.preventDefault();
@@ -25,6 +38,7 @@ export function useBlockNavigation(message: string) {
setIsBlocking(false);
};
}, [location]);
+
useEffect(() => {
window.addEventListener("beforeunload", handleBeforeUnload);
@@ -33,5 +47,5 @@ export function useBlockNavigation(message: string) {
};
}, [isBlocking]);
- return { unblockNavigation };
+ return { unblockNavigation, isBlockedNavigation, proceedNavigation, cancelNavigation };
}
diff --git a/client/src/hooks/usePopup.tsx b/client/src/hooks/usePhoneNumberPopup.tsx
similarity index 81%
rename from client/src/hooks/usePopup.tsx
rename to client/src/hooks/usePhoneNumberPopup.tsx
index 7173a039..b7c85f0c 100644
--- a/client/src/hooks/usePopup.tsx
+++ b/client/src/hooks/usePhoneNumberPopup.tsx
@@ -1,11 +1,11 @@
import { useEffect, useState } from "react";
-import Popup, { PopUpProps } from "@/components/PopUp";
+import PhoneNumberPopUp, { PhoneNumberPopUpProps } from "@/components/PhoneNumberPopUp";
-export default function usePopup({
+export default function usePhoneNumberPopUp({
phoneNumber,
handlePhoneNumberChange,
handlePhoneNumberConfirm,
-}: Omit) {
+}: Omit) {
const [isVisible, setIsVisible] = useState(false);
useEffect(() => {
@@ -26,7 +26,7 @@ export default function usePopup({
};
const PopupComponent = isVisible ? (
-
+
+ {isBlockedNavigation && (
+
+ )}
);
}
diff --git a/client/src/pages/Lottery/index.tsx b/client/src/pages/Lottery/index.tsx
index cca523f5..6712f1a3 100644
--- a/client/src/pages/Lottery/index.tsx
+++ b/client/src/pages/Lottery/index.tsx
@@ -16,7 +16,7 @@ import {
} from "@/features/Lottery";
import { useAuth } from "@/hooks/useAuth.ts";
import useHeaderStyleObserver from "@/hooks/useHeaderStyleObserver.ts";
-import usePopup from "@/hooks/usePopup";
+import usePhoneNumberPopUp from "@/hooks/usePhoneNumberPopup";
import useScrollToTarget from "@/hooks/useScrollToTarget";
import useScrollTop from "@/hooks/useScrollTop";
import useToast from "@/hooks/useToast";
@@ -36,7 +36,7 @@ export default function Lottery() {
const { phoneNumberState, handlePhoneNumberChange, handlePhoneNumberConfirm } =
useAuth("/lottery/custom");
- const { handleOpenPopup, PopupComponent } = usePopup({
+ const { handleOpenPopup, PopupComponent } = usePhoneNumberPopUp({
phoneNumber: phoneNumberState,
handlePhoneNumberChange,
handlePhoneNumberConfirm,
diff --git a/client/src/pages/RushGame/index.tsx b/client/src/pages/RushGame/index.tsx
index d3d8ac44..25341583 100644
--- a/client/src/pages/RushGame/index.tsx
+++ b/client/src/pages/RushGame/index.tsx
@@ -11,14 +11,10 @@ import useRushGameStateContext from "@/hooks/Contexts/useRushGameStateContext.ts
import { useFetchRushUserParticipationStatus } from "@/hooks/RushGame/useFetchRushUserParticipationStatus.ts";
import { useFetchTodayRushEvent } from "@/hooks/RushGame/useFetchTodayRushEvent.ts";
import useSetGamePhase from "@/hooks/RushGame/useSetGamePhase.ts";
-import { useBlockNavigation } from "@/hooks/useBlockNavigation.ts";
import { GetTotalRushEventsResponse } from "@/types/rushApi.ts";
export default function RushGame() {
const [cookies] = useCookies([COOKIE_KEY.ACCESS_TOKEN]);
- const { unblockNavigation } = useBlockNavigation(
- "이 페이지를 떠나면 모든 변경 사항이 저장되지 않습니다. 페이지를 떠나시겠습니까?"
- );
const { getTodayRushEvent } = useFetchTodayRushEvent();
const gameState = useRushGameStateContext();
const { getRushUserParticipationStatus, userParticipatedStatus } =
@@ -43,11 +39,11 @@ export default function RushGame() {
if (!gameState.userParticipatedStatus) {
return ;
} else {
- return ;
+ return ;
}
}
case CARD_PHASE.COMPLETED:
- return ;
+ return ;
default:
return null;
}