Skip to content

Commit

Permalink
Merge pull request #193 from softeerbootcamp4th/feat/#191-block-popup
Browse files Browse the repository at this point in the history
[Feat] Navigation Block 팝업 커스텀 구현
  • Loading branch information
sooyeoniya authored Aug 22, 2024
2 parents 7c05761 + 4387eb7 commit 138a0ab
Show file tree
Hide file tree
Showing 12 changed files with 104 additions and 39 deletions.
10 changes: 10 additions & 0 deletions client/src/components/NavigationConfirmPopup/index.style.ts
Original file line number Diff line number Diff line change
@@ -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",
},
},
});
48 changes: 48 additions & 0 deletions client/src/components/NavigationConfirmPopup/index.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<div className="fixed w-full h-full left-0 top-0 z-20">
<div
className="absolute left-0 top-0 w-[100%] h-[100%] bg-n-black/[.4]"
onClick={handleClose}
/>
<div className="px-[50px] py-1000 bg-n-white rounded-600 absolute left-[50%] top-[50%] translate-y-[-50%] translate-x-[-50%]">
<p className="h-body-1-regular">
이 페이지를 떠나면 모든 변경 사항이 저장되지 않습니다.
<br />
페이지를 떠나시겠습니까?
</p>

<div className="flex gap-500 mt-800">
<button className={buttonStyles({ variant: "primary" })} onClick={handleClose}>
아니요
</button>
<button
className={buttonStyles({ variant: "secondary" })}
onClick={handleConfirm}
>
</button>
</div>
</div>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -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",
Expand All @@ -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) => {
Expand All @@ -32,7 +32,7 @@ const PopUp = (args: PopUpProps) => {
);
};

export const Default = (args: PopUpProps) => (
export const Default = (args: PhoneNumberPopUpProps) => (
<>
<PopUp {...args} />
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions client/src/features/Rush/Common/Headline.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand All @@ -67,7 +63,6 @@ export default function SelectedCard({ unblockNavigation }: SelectedCardProps) {

useEffect(() => {
fetchRushBalance();
unblockNavigation();
}, []);

return (
Expand Down
22 changes: 18 additions & 4 deletions client/src/hooks/useBlockNavigation.ts
Original file line number Diff line number Diff line change
@@ -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();
Expand All @@ -25,6 +38,7 @@ export function useBlockNavigation(message: string) {
setIsBlocking(false);
};
}, [location]);

useEffect(() => {
window.addEventListener("beforeunload", handleBeforeUnload);

Expand All @@ -33,5 +47,5 @@ export function useBlockNavigation(message: string) {
};
}, [isBlocking]);

return { unblockNavigation };
return { unblockNavigation, isBlockedNavigation, proceedNavigation, cancelNavigation };
}
Original file line number Diff line number Diff line change
@@ -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<PopUpProps, "handleClose">) {
}: Omit<PhoneNumberPopUpProps, "handleClose">) {
const [isVisible, setIsVisible] = useState(false);

useEffect(() => {
Expand All @@ -26,7 +26,7 @@ export default function usePopup({
};

const PopupComponent = isVisible ? (
<Popup
<PhoneNumberPopUp
phoneNumber={phoneNumber}
handlePhoneNumberChange={handlePhoneNumberChange}
handlePhoneNumberConfirm={handlePhoneNumberConfirm}
Expand Down
13 changes: 10 additions & 3 deletions client/src/pages/CasperCustom/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useState } from "react";
import { motion } from "framer-motion";
import NavigationConfirmPopUp from "@/components/NavigationConfirmPopup";
import {
CUSTOM_STEP_HEADLINE,
CUSTOM_STEP_OPTION,
Expand All @@ -21,9 +22,8 @@ import useHeaderStyleObserver from "@/hooks/useHeaderStyleObserver";
const INITIAL_STEP = 0;

export default function CasperCustom() {
const { unblockNavigation } = useBlockNavigation(
"이 페이지를 떠나면 모든 변경 사항이 저장되지 않습니다. 페이지를 떠나시겠습니까?"
);
const { unblockNavigation, isBlockedNavigation, proceedNavigation, cancelNavigation } =
useBlockNavigation();

const containerRef = useHeaderStyleObserver({
darkSections: [CASPER_CUSTOM_SECTIONS.CUSTOM],
Expand Down Expand Up @@ -82,6 +82,13 @@ export default function CasperCustom() {
{renderCustomStep()}
</section>
</div>

{isBlockedNavigation && (
<NavigationConfirmPopUp
handleConfirm={proceedNavigation}
handleClose={cancelNavigation}
/>
)}
</CasperCustomProvider>
);
}
4 changes: 2 additions & 2 deletions client/src/pages/Lottery/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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,
Expand Down
8 changes: 2 additions & 6 deletions client/src/pages/RushGame/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 } =
Expand All @@ -43,11 +39,11 @@ export default function RushGame() {
if (!gameState.userParticipatedStatus) {
return <CardOptions />;
} else {
return <SelectedCard unblockNavigation={unblockNavigation} />;
return <SelectedCard />;
}
}
case CARD_PHASE.COMPLETED:
return <FinalResult unblockNavigation={unblockNavigation} />;
return <FinalResult />;
default:
return null;
}
Expand Down

0 comments on commit 138a0ab

Please sign in to comment.