Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feat] RacingGame 응모 로직 구현 #30

Merged
merged 13 commits into from
Aug 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Caecae/public/assets/customSelectDescription.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions Caecae/public/assets/customSelectDescriptionFocus.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
962 changes: 962 additions & 0 deletions Caecae/public/assets/racingGameEnterImage.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { ChangeEventHandler, useEffect, useState } from "react";
import { action } from "../../jobs/Overlay/OverlayWork";
import { store } from "../../shared/Hyundux";

const PhoneNumberOverlay = () => {
const PhoneNumberOverlayFindingGame = () => {
const [timeLeft, setTimeLeft] = useState(3 * 60); // 3분을 초 단위로 변환
const [phoneNumber, setPhoneNumber] = useState("");
const [check, setCheck] = useState(false);
Expand Down Expand Up @@ -77,30 +77,30 @@ const PhoneNumberOverlay = () => {

return (
<div className="flex flex-col h-full w-full">
<div className="pl-[59px] pr-[59px] grow pl-[60px] pt-[80px]">
<p className="text-2xl font-medium">전화번호 입력</p>
<div className="pl-[60px] pr-[59px] grow pt-[80px]">
<p className="text-[32px] font-bold text-[#1C1A1B]">전화번호 입력</p>
<div className="mt-[7px]">
<span className="text-[red] underline">
<span className="text-[red] underline mt-[10px]">
<span>{timeToString()}</span>내
</span>
<span>에 입력하지 않으면 미당첨으로 간주되어 자동 종료됩니다.</span>
</div>
<div className="flex items-center mt-[45px] justify-between">
<p className="font-medium font-xl mr-[80px]">전화번호</p>
<p className="font-bold text-[20px] text-[#1C1A1B] mr-[80px]">전화번호</p>
<input
type="text"
value={phoneNumber}
onChange={onPhoneNumberFieldChange}
placeholder={""}
className="border border-gray-300 bg-white py-2 px-4 text-base focus:focus:border-[#002C5F] w-[600px] h-[55px]"
className="border border-gray-300 bg-white py-2 px-4 text-base focus:focus:border-[#002C5F] w-[700px] h-[55px]"
/>
</div>
<div className="flex mt-[45px] justify-between">
<p className="font-medium font-xl mr-[80px] pt-[12px]">
<p className="font-bold text-[20px] text-[#1C1A1B] mr-[80px] pt-[12px]">
개인정보 동의
</p>
<div>
<div className="border border-gray-300 bg-white py-2 px-4 w-[600px] h-[140px] overflow-scroll">
<div className="border border-gray-300 bg-white py-2 px-4 w-[700px] h-[140px] overflow-scroll">
<p>
1. 개인정보의 처리 목적
<br />
Expand All @@ -122,14 +122,14 @@ const PhoneNumberOverlay = () => {
<br />
</p>
</div>
<div className="flex mt-[10px] items-center">
<div className="flex mt-[20px] items-center">
<input
type="checkbox"
checked={check}
onChange={onCheckboxChange}
className="form-checkbox h-4 w-4 text-[#002C5F] border-[#DDD] bg-neutral-white mr-[5px]"
/>
<p>
<p className="ml-2">
개인정보보호법에 따라 귀하의 개인정보를 다음과 같이
수집・이용하는데 동의합니다.
</p>
Expand All @@ -151,4 +151,4 @@ const PhoneNumberOverlay = () => {
);
};

export default PhoneNumberOverlay;
export default PhoneNumberOverlayFindingGame;
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import { ChangeEventHandler, useEffect, useState } from "react";
import { action } from "../../jobs/Overlay/OverlayWork";
import { store } from "../../shared/Hyundux";

const PhoneNumberOverlayRacingGame = () => {
const [phoneNumber, setPhoneNumber] = useState("");
const [check, setCheck] = useState(false);
const [enterable, setEnterable] = useState(false);

const onPhoneNumberFieldChange: ChangeEventHandler<HTMLInputElement> = (
event
) => {
let number = "";
const cleaned = event.target.value.replace(/\D/g, "");

// 유효성 검사
if (cleaned.length <= 3) {
number = cleaned;
setPhoneNumber(number);
} else if (cleaned.length <= 7) {
number = `${cleaned.slice(0, 3)}-${cleaned.slice(3)}`;
setPhoneNumber(number);
} else if (cleaned.length <= 11) {
number = `${cleaned.slice(0, 3)}-${cleaned.slice(3, 7)}-${cleaned.slice(
7,
11
)}`;
if (cleaned.length == 11) {
console.log(1234123);
}
setPhoneNumber(number);
}
};

const onCheckboxChange: ChangeEventHandler<HTMLInputElement> = () => {
setCheck((prev) => !prev);
};

useEffect(() => {
const number = phoneNumber.split("-").join("");
if (
check &&
number.length == 11 &&
number.slice(0, 3) === "010" &&
enterable === false
) {
setEnterable(true);
} else if (enterable === true) {
setEnterable(false);
}
}, [check, phoneNumber]);

return (
<div className="flex flex-col h-full w-full">
<div className="pl-[60px] pr-[59px] grow pt-[80px]">
<p className="text-[32px] font-bold text-[#1C1A1B]">전화번호 입력</p>
<div className="text-[#444444] mt-[10px]">
<span>경품 수령을 위해 간단한 정보를 입력해 주세요.</span>
</div>
<div className="flex items-center mt-[45px] justify-between">
<p className="font-bold text-[20px] text-[#1C1A1B] mr-[80px]">전화번호</p>
<input
type="text"
value={phoneNumber}
onChange={onPhoneNumberFieldChange}
placeholder={""}
className="border border-gray-300 bg-white py-2 px-4 text-base focus:focus:border-[#002C5F] w-[700px] h-[55px]"
/>
</div>
<div className="flex mt-[45px] justify-between">
<p className="font-bold text-[20px] text-[#1C1A1B] mr-[80px] pt-[12px]">
개인정보 동의
</p>
<div>
<div className="border border-gray-300 bg-white py-2 px-4 w-[700px] h-[140px] overflow-scroll">
<p>
1. 개인정보의 처리 목적
<br />
개인정보를 다음의 목적을 위해 처리합니다. 처리한 개인정보는
다음의 목적 이외의 용도로는 사용되지 않으며 이용 목적이 변경될
시에는 사전 동의를 구할 예정입니다.
<br />
1. 개인정보의 처리 목적
<br />
개인정보를 다음의 목적을 위해 처리합니다. 처리한 개인정보는
다음의 목적 이외의 용도로는 사용되지 않으며 이용 목적이 변경될
시에는 사전 동의를 구할 예정입니다.
<br />
1. 개인정보의 처리 목적
<br />
개인정보를 다음의 목적을 위해 처리합니다. 처리한 개인정보는
다음의 목적 이외의 용도로는 사용되지 않으며 이용 목적이 변경될
시에는 사전 동의를 구할 예정입니다.
<br />
</p>
</div>
<div className="flex mt-[20px] items-center">
<input
type="checkbox"
checked={check}
onChange={onCheckboxChange}
className="form-checkbox h-4 w-4 text-[#002C5F] border-[#DDD] bg-neutral-white mr-[5px]"
/>
<p className="ml-2">
개인정보보호법에 따라 귀하의 개인정보를 다음과 같이
수집・이용하는데 동의합니다.
</p>
</div>
</div>
</div>
</div>
<div
onClick={() => {
store.dispatch(action.nextPage());
}}
className={`bg-[${
enterable ? "#002C5F" : "#CCCCCC"
}] h-[12%] flex items-center justify-center`}
>
<p className="text-[white] text-[20px] font-bold">응모 완료가기</p>
</div>
</div>
);
};

export default PhoneNumberOverlayRacingGame;
6 changes: 4 additions & 2 deletions Caecae/src/components/PhoneNumberOverlay/index.tsx
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
import PhoneNumberOverlay from "./PhoneNumberOverlay";
export default PhoneNumberOverlay;
import PhoneNumberOverlayFindingGame from "./PhoneNumberOverlayFindingGame";
import PhoneNumberOverlayRacingGame from "./PhoneNumberOverlayRacingGame";

export default { PhoneNumberOverlayFindingGame, PhoneNumberOverlayRacingGame };
47 changes: 34 additions & 13 deletions Caecae/src/components/RacingGame/RacingGame.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,21 @@ import React, { useRef, useState, useEffect } from "react";
import Lottie, { LottieRefCurrentProps } from "lottie-react";
import { motion, useAnimation, useMotionValue } from "framer-motion";
import animationGame315 from "@assets/animationGame315.json";
import frontBackground from "../../../assets/frontBackground.svg";
import rearBackground from "../../../assets/rearBackground.svg";
import frontBackground from "@assets/frontBackground.svg";
import rearBackground from "@assets/rearBackground.svg";
import {
action,
initRacingGameState,
racingGameReducer,
initRacingGameState
} from "../../jobs/RacingGame/RacingGameWork.tsx";
import { useWork, store } from "../../shared/Hyundux/index.tsx";
import { store, useExistState } from "../../shared/Hyundux/index.tsx";
import Link from "../../shared/Hyunouter/Link.tsx";

/** 게임 상태에 따라 다르게 보여지는 콘텐츠 */
const gameContent = (
gameStatus: string,
distance: number,
handlePlayGame: () => void
handlePlayGame: () => void,
enterEvent: () => void
) => {
switch (gameStatus) {
case "previous":
Expand Down Expand Up @@ -63,24 +63,40 @@ const gameContent = (
<div className="flex flex-row items-center justify-center mt-2 space-x-4">
<button
className=""
// onClick={}
onClick={enterEvent}
>
<img
className="h-[50px]"
src="assets/enterEventBtn.svg"
src="public/assets/enterEventBtn.svg"
alt="enterEventBtn"
/>
</button>
<button className="" onClick={handlePlayGame}>
<img
className="h-[50px]"
src="assets/retryBtn.svg"
src="public/assets/retryBtn.svg"
alt="retryBtn"
/>
</button>
</div>
</div>
);
case "enterEvent":
return (
<div className="absolute left-[650px] top-[70px] z-40 flex flex-col items-center justify-center">
<div className="font-bold text-xl mb-2">CASPER ELECTRIC</div>
<div className="font-bold text-xl mb-2">전력으로...!</div>
<div className="mt-2">
<button className="" onClick={handlePlayGame}>
<img
className="w-[300px] h-[55px]"
src="public/assets/gameStartBtn.svg"
alt="gameStartBtn"
/>
</button>
</div>
</div>
);
default:
return null;
}
Expand Down Expand Up @@ -125,7 +141,8 @@ const RacingGame: React.FC = () => {
const rearRef = useRef<HTMLDivElement>(null);
const [frontBackgroundWidth, setFrontImageWidth] = useState<number>(0);
const [rearBackgroundWidth, setRearBackgroundWidth] = useState<number>(0);
const [state, dispatch] = useWork(initRacingGameState, racingGameReducer);
// const [state, dispatch] = useWork(initRacingGameState, racingGameReducer);
const state = useExistState(initRacingGameState);

/** 모션 값을 사용하여 frontBackground의 x 위치 추적 */
const frontX = useMotionValue(0);
Expand All @@ -137,7 +154,7 @@ const RacingGame: React.FC = () => {
/** 이동한 km를 구하는 함수 */
const calculateDistance = (x: number) => {
const totalDistance = Math.abs(x);
dispatch;

store.dispatch(action.updateDistance(totalDistance));
};

Expand Down Expand Up @@ -198,6 +215,10 @@ const RacingGame: React.FC = () => {
}
};

const enterEvent = () => {
store.dispatch(action.enterEvent());
}

/** 2개의 백그라운드 이미지의 width를 구하는 로직 */
useEffect(() => {
const frontBackgroundImg = new Image();
Expand Down Expand Up @@ -262,10 +283,10 @@ const RacingGame: React.FC = () => {
autoplay={false}
className="absolute top-[485px] left-[250px] w-[350px] h-auto z-[3]"
/>
{gameContent(state.gameStatus, state.distance, handlePlayGame)}
{gameContent(state.gameStatus, state.distance, handlePlayGame, enterEvent)}
{gameMenu(state.gameStatus)}
</div>
);
};

export default RacingGame;
export default RacingGame;
3 changes: 3 additions & 0 deletions Caecae/src/components/RacingGame/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import RacingGame from "./RacingGame";

export default RacingGame;
4 changes: 2 additions & 2 deletions Caecae/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import EventInfoLandingPage from "./pages/EventInfoLanding/EventInfoLandingPage.
import FindingGameLandingPage from "./pages/FindingGameLanding/FindingGameLandingPage.tsx";
import RacingGameLandingPage from "./pages/RacingGameLanding/RacingGameLandingPage.tsx";
import FindingGamePage from "./pages/FindingGame/FindingGamePage.tsx";
import RacingGame from "./components/RacingGame/RacingGame.tsx";
import RacingGamePage from "./pages/RacingGame/RacingGamePage.tsx";

// 임시 React component
const App = () => {
Expand All @@ -20,7 +20,7 @@ const App = () => {
path="/findcaspergame#010643431936"
element={<FindingGamePage />}
/>
<Route path="/racecaspergame" element={<RacingGame />} />
<Route path="/racecaspergame" element={<RacingGamePage />} />
</Routes>
</Router>
</div>
Expand Down
12 changes: 10 additions & 2 deletions Caecae/src/jobs/RacingGame/RacingGameWork.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const aniMovingDistance = 11990;

// state type
interface RacingGamePayLoad {
gameStatus: "previous" | "playing" | "end";
gameStatus: "previous" | "playing" | "end" | "enterEvent";
distance: number;
}

Expand All @@ -34,7 +34,9 @@ const racingGameReducer: Reducer<RacingGamePayLoad> = {
return makePayLoad(state, {
distance: (actionPayLoad.distance / aniMovingDistance) * km315,
});
}
};
case "enterEvent":
return makePayLoad(state, { gameStatus: "enterEvent" });
default:
return state;
}
Expand Down Expand Up @@ -64,6 +66,12 @@ const action = {
},
};
},
enterEvent: (): Action => {
return {
type: WORKFLOW_NAME,
actionName: "enterEvent",
};
},
};

export { action, initRacingGameState, racingGameReducer };
Loading
Loading