);
+ clearInterval(intervalId!);
};
+ const goBack = () => {
+ setIsOver(false);
+ };
+
+ useEffect(() => {
+ if (localStorage.getItem("time") != null) {
+ setTime(parseInt(localStorage.getItem("time")!));
+ setIntervalId(
+ setInterval(() => {
+ setTime((prevState) => {
+ const newTime = (prevState as number) + 1;
+ localStorage.setItem("time", newTime.toString());
+ return newTime;
+ });
+ }, 1000)
+ );
+ }
+ if (localStorage.getItem("studentNumber") != null) {
+ setStudentNumber(localStorage.getItem("studentNumber")!);
+ }
+ }, []);
+
return (
{time !== null && (
@@ -60,7 +90,13 @@ export default function App() {
)}
{/*
클리어 타임: {secondsToMMSS(123)}
*/}
@@ -68,11 +104,23 @@ export default function App() {
} />
} />
} />
- } />
+ }
+ />
} />
} />
} />
} />
+
+ } />
+ }
+ />
+ } />
+ } />
+
diff --git a/src/pages/birthday_page.scss b/src/pages/birthday_page.scss
new file mode 100644
index 0000000..a4473d1
--- /dev/null
+++ b/src/pages/birthday_page.scss
@@ -0,0 +1,206 @@
+HTML {
+ --rotate: 0deg;
+ --rotate2: 0deg;
+ --rotate3: 0deg;
+}
+
+.play {
+ position: absolute;
+ background-color: white;
+ right: 1rem;
+ bottom: 1rem;
+ padding: 1rem;
+ border-radius: 1rem;
+ cursor: pointer;
+}
+
+.overlay {
+ text-align: center;
+ position: absolute;
+ top: 2rem;
+ left: 50vw;
+ font-size: 1.25rem;
+ transform: translateX(-50%);
+ color: white;
+}
+
+.wrapper {
+ width: 100vw;
+ height: 100vh;
+ background-color: black;
+}
+
+.layout {
+ // background-color: black;
+ width: 100%;
+ height: 110%;
+ position: fixed;
+ left: 0;
+ top: -10%;
+ border: 3px solid black;
+}
+
+.Day_Button {
+ border-top: 5px solid white;
+ border-bottom: 5px solid white;
+ width: 80px;
+ height: 80px;
+ color: white;
+ background-color: black;
+ font-size: 40px;
+ font-weight: bold;
+ position: fixed;
+ left: 91%;
+ top: 80%;
+ text-align: center;
+ line-height: 80px;
+ border-radius: 10%;
+}
+
+.Day_Text {
+ font-size: 16px;
+ position: fixed;
+ top: 79.5%;
+ left: 92.5%;
+ color: white;
+}
+.Month_Button {
+ border-top: 5px solid white;
+ border-bottom: 5px solid white;
+ width: 80px;
+ height: 80px;
+ color: white;
+ background-color: black;
+ font-size: 40px;
+ font-weight: bold;
+ position: fixed;
+ left: 81.55%;
+ top: 80%;
+ text-align: center;
+ line-height: 80px;
+ border-radius: 10%;
+}
+
+.Month_Text {
+ font-size: 16px;
+ position: fixed;
+ top: 79.5%;
+ left: 82.5%;
+ color: white;
+}
+
+.Year_Button {
+ border-top: 5px solid white;
+ border-bottom: 5px solid white;
+ width: 160px;
+ height: 80px;
+ color: white;
+ background-color: black;
+ font-size: 40px;
+ font-weight: bold;
+ position: fixed;
+ left: 66%;
+ top: 80%;
+ text-align: center;
+ line-height: 80px;
+ border-radius: 10%;
+}
+
+.Year_Text {
+ font-size: 16px;
+ position: fixed;
+ top: 79.5%;
+ left: 70%;
+ color: white;
+}
+
+/*Month*/
+.ModeChanger {
+ color: white;
+ background-color: black;
+ white-space: pre-wrap;
+ text-align: center;
+ position: fixed;
+ left: calc(100% - 220px);
+ top: 50%;
+ font-size: 16px;
+ width: 200px;
+ height: 75px;
+ line-height: 25px;
+ border: 3px solid white;
+}
+
+.Moon {
+ rotate: var(--rotate2);
+ position: fixed;
+ left: calc(50% - 300px);
+ top: calc(50% - 500px);
+}
+
+.Sun {
+ rotate: var(--rotate3);
+ position: fixed;
+ left: -2400px;
+ top: -1000px;
+}
+
+/*Day*/
+
+.Earth {
+ rotate: var(--rotate);
+ position: fixed;
+ left: calc(50% + 50px);
+ top: calc(50% - 150px);
+ transform: scale(60%, 60%);
+}
+
+.circle_box {
+ /*background-color: lightgray;*/
+ width: 180px;
+ height: 180px;
+ border-radius: 150px;
+ position: fixed;
+ left: calc(50% + 110px);
+ top: calc(50% - 105px);
+ opacity: 0.3;
+}
+
+.circle_box2 {
+ /*background-color: red;*/
+ width: 1000px;
+ height: 1000px;
+ border-radius: 500px;
+ position: fixed;
+ left: calc(50% - 300px);
+ top: calc(50% - 510px);
+ opacity: 0.3;
+}
+
+.circle_box3 {
+ /*background-color: green;*/
+ width: 3000px;
+ height: 3000px;
+ border-radius: 1500px;
+ position: fixed;
+ left: -2650px;
+ top: -1000px;
+ opacity: 0.3;
+}
+
+.Spin_Power_Text {
+ color: white;
+ position: fixed;
+ top: 15%;
+ white-space: pre-wrap;
+}
+
+.UnClick_Circle {
+ /*background-color: blue;*/
+ width: 700px;
+ height: 700px;
+ border-radius: 50%;
+ position: fixed;
+ left: calc(50% - 150px);
+ top: calc(50% - 350px);
+ opacity: 0.3;
+}
diff --git a/src/pages/birthday_page.tsx b/src/pages/birthday_page.tsx
index ca58dfa..0bfb3d1 100644
--- a/src/pages/birthday_page.tsx
+++ b/src/pages/birthday_page.tsx
@@ -1,19 +1,405 @@
import { useNavigate } from "react-router";
-const BirthdayPage = () => {
+import "./birthday_page.scss";
+import { useState } from "react";
+import Portal from "../components/UI/Portal";
+import { useNotification } from "../components/notification/NotificationProvider";
+
+type PropsType = {
+ nextLink: string;
+};
+
+const BirthdayPage = ({ nextLink }: PropsType) => {
+ const Rotate_Times1 = 0.5;
+ const Rotate_Times2 = 15;
+ const Rotate_Times3 = 1;
+
+ const notice = useNotification();
+
const navigate = useNavigate();
- const onSubmit = () => {
- navigate("/email");
- };
+ let Rotate_CSS_Day = 0;
+ let Rotate_CSS_Month = 0;
+ let Rotate_CSS_Year = 0;
+ let [Earth_Spin_Power, setEarth_Spin_Power] = useState(0);
+ let [Moon_Spin_Power, setMoon_Spin_Power] = useState(0);
+ let [Sun_Spin_Power, setSun_Spin_Power] = useState(0);
+ const rootStyles = window.getComputedStyle(document.documentElement);
+
+ let [Now_Day, setNow_Day] = useState("1");
+ let [Now_Month, setNow_Month] = useState("1");
+ let [Now_Year, setNow_Year] = useState("1924");
+
+ function Layout1() {
+ return (
+
+ );
+ }
+
+ function Earth() {
+ return (
+
+ );
+ }
+
+ function Sun() {
+ return (
+
+ );
+ }
+
+ function Moon() {
+ return (
+
+ );
+ }
+
+ //times
+ function DayButton() {
+ return (
+
+ {Now_Day}
+
+ );
+ }
+
+ function DayText() {
+ return (
+
+ Day
+
+ );
+ }
+
+ function MonthButton() {
+ return (
+
+ {-Now_Month}
+
+ );
+ }
+
+ function MonthText() {
+ return (
+
+ Month
+
+ );
+ }
+
+ function YearButton() {
+ return (
+
+ {Now_Year}
+
+ );
+ }
+
+ function YearText() {
+ return (
+
+ Year
+
+ );
+ }
+
+ function MOverAll() {
+ MOver3();
+ Rotate_CSS_Day = parseInt(rootStyles.getPropertyValue("--rotate"));
+ Rotate_CSS_Month = parseInt(rootStyles.getPropertyValue("--rotate2"));
+
+ setNow_Month(
+ `${
+ Math.floor(Rotate_CSS_Month / -360) % 12 !== 0
+ ? Math.floor(Rotate_CSS_Month / -360) % 12
+ : -12
+ }`
+ );
+ setNow_Day(
+ `${
+ Math.floor(Rotate_CSS_Day / -360) % 31 !== 0
+ ? Math.floor(Rotate_CSS_Day / -360) % 31
+ : 31
+ }`
+ );
+ if (Moon_Spin_Power > 1 && Earth_Spin_Power < -1) {
+ setMoon_Spin_Power(Moon_Spin_Power - 1);
+ document.documentElement.style.setProperty(
+ "--rotate2",
+ `${Rotate_CSS_Month + Moon_Spin_Power / Rotate_Times2}deg`
+ );
+ setEarth_Spin_Power(Earth_Spin_Power + 1);
+ document.documentElement.style.setProperty(
+ "--rotate",
+ `${Rotate_CSS_Day + Earth_Spin_Power / Rotate_Times1}deg`
+ );
+ } else if (Moon_Spin_Power <= 1 && Earth_Spin_Power >= -1) {
+ setMoon_Spin_Power(0);
+ document.documentElement.style.setProperty(
+ "--rotate2",
+ `${Rotate_CSS_Month + Moon_Spin_Power / Rotate_Times2}deg`
+ );
+ setEarth_Spin_Power(0);
+ document.documentElement.style.setProperty(
+ "--rotate",
+ `${Rotate_CSS_Day + Earth_Spin_Power / Rotate_Times1}deg`
+ );
+ } else if (Moon_Spin_Power > 1 && Earth_Spin_Power >= -1) {
+ setMoon_Spin_Power(Moon_Spin_Power - 1);
+ document.documentElement.style.setProperty(
+ "--rotate2",
+ `${Rotate_CSS_Month + Moon_Spin_Power / Rotate_Times2}deg`
+ );
+ setEarth_Spin_Power(0);
+ document.documentElement.style.setProperty(
+ "--rotate",
+ `${Rotate_CSS_Day + Earth_Spin_Power / Rotate_Times1}deg`
+ );
+ } else {
+ setMoon_Spin_Power(0);
+ document.documentElement.style.setProperty(
+ "--rotate2",
+ `${Rotate_CSS_Month + Moon_Spin_Power / Rotate_Times2}deg`
+ );
+ setEarth_Spin_Power(Earth_Spin_Power + 1);
+ document.documentElement.style.setProperty(
+ "--rotate",
+ `${Rotate_CSS_Day + Earth_Spin_Power / Rotate_Times1}deg`
+ );
+ }
+ }
+
+ function MOver3() {
+ Rotate_CSS_Year = parseInt(rootStyles.getPropertyValue("--rotate3"));
+ setNow_Year(
+ `${Math.floor(
+ Math.floor(Rotate_CSS_Year / 360) % 200 === 0
+ ? 1924
+ : ((Rotate_CSS_Year / 360) % 200) + 1924
+ )}`
+ );
+
+ if (Sun_Spin_Power > 1) {
+ setSun_Spin_Power(Sun_Spin_Power - 1);
+ document.documentElement.style.setProperty(
+ "--rotate3",
+ `${Rotate_CSS_Year + Sun_Spin_Power / Rotate_Times3}deg`
+ );
+ } else {
+ setSun_Spin_Power(0);
+ document.documentElement.style.setProperty(
+ "--rotate3",
+ `${Rotate_CSS_Year + Sun_Spin_Power / Rotate_Times3}deg`
+ );
+ }
+ }
+
+ //month
+ function MOver2() {
+ Rotate_CSS_Month = parseInt(rootStyles.getPropertyValue("--rotate2"));
+ setNow_Month(
+ `${Math.floor(
+ Math.floor(Rotate_CSS_Month / -360) % 12 !== 0
+ ? Math.floor(Rotate_CSS_Month / -360) % 12
+ : -12
+ )}`
+ );
+
+ if (Moon_Spin_Power > 1) {
+ setMoon_Spin_Power(Moon_Spin_Power - 1);
+ document.documentElement.style.setProperty(
+ "--rotate2",
+ `${Rotate_CSS_Month + Moon_Spin_Power / Rotate_Times2}deg`
+ );
+ } else {
+ setMoon_Spin_Power(0);
+ document.documentElement.style.setProperty(
+ "--rotate2",
+ `${Rotate_CSS_Month + Moon_Spin_Power / Rotate_Times2}deg`
+ );
+ }
+ }
+
+ //Day
+ function MOver() {
+ Rotate_CSS_Day = parseInt(rootStyles.getPropertyValue("--rotate"));
+ setNow_Day(
+ `${Math.floor(
+ Math.floor(Rotate_CSS_Day / -360) % 31 !== 0
+ ? Math.floor(Rotate_CSS_Day / -360) % 31
+ : 31
+ )}`
+ );
+
+ if (Earth_Spin_Power < -1) {
+ setEarth_Spin_Power(Earth_Spin_Power + 1);
+ document.documentElement.style.setProperty(
+ "--rotate",
+ `${Rotate_CSS_Day + Earth_Spin_Power / Rotate_Times1}deg`
+ );
+ } else {
+ setEarth_Spin_Power(0);
+ document.documentElement.style.setProperty(
+ "--rotate",
+ `${Rotate_CSS_Day + Earth_Spin_Power / Rotate_Times1}deg`
+ );
+ }
+ }
+
+ function UnClickCircle() {
+ return
;
+ }
+
+ function CircleDay() {
+ return (
+
+ );
+ }
+
+ function CircleMonth() {
+ return (
+
+ );
+ }
+
+ function CircleYear() {
+ return (
+
+ );
+ }
+
+ //set
+
+ function Times() {
+ return (
+
+
+
+
+
+
+
+
+ );
+ }
+
+ function submitHandler() {
+ notice({ type: "SUCCESS", message: "생일 입력 성공!" });
+ navigate(nextLink);
+ }
return (
-
- 생일
-
- 넘어가기
-
-
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 넘어가기
+
+
+
+
+ 각 천체에 마우스를 가져다 대 생일을 입력하세요!
+
+ 태양은 연도, 달은 월, 지구는 일을 변경합니다
+
+ Tip: 달은 달 궤도 사이에 마우스를 놓으면 이동합니다!
+
+
+ >
);
};
diff --git a/src/pages/dorm_room_page.module.scss b/src/pages/dorm_room_page.module.scss
new file mode 100644
index 0000000..66a0830
--- /dev/null
+++ b/src/pages/dorm_room_page.module.scss
@@ -0,0 +1,21 @@
+.unity {
+ width: 80vw !important;
+ height: 80vh !important;
+}
+
+
+.wrapper {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+
+ h1 {
+ margin-top: 0;
+ }
+}
+.overlay {
+ position: absolute;
+ top: 1rem;
+ left: 50%;
+ transform: translateX(-50%);
+}
\ No newline at end of file
diff --git a/src/pages/dorm_room_page.tsx b/src/pages/dorm_room_page.tsx
index 774c28b..7060ca9 100644
--- a/src/pages/dorm_room_page.tsx
+++ b/src/pages/dorm_room_page.tsx
@@ -1,18 +1,50 @@
import { useNavigate } from "react-router";
+import classes from "./dorm_room_page.module.scss";
+import { Unity, useUnityContext } from "react-unity-webgl";
+import {
+ SetStateAction,
+ useCallback,
+ useContext,
+ useEffect,
+ useState,
+} from "react";
+import { useNotification } from "../components/notification/NotificationProvider";
+import Portal from "../components/UI/Portal";
const DormRoomPage = () => {
const navigate = useNavigate();
+ const notice = useNotification();
- const onSubmit = () => {
+ const { unityProvider } = useUnityContext({
+ loaderUrl: "dorm_unity_build/HaksulUnityBuild.loader.js",
+ dataUrl: "dorm_unity_build/HaksulUnityBuild.data",
+ frameworkUrl: "dorm_unity_build/HaksulUnityBuild.framework.js",
+ codeUrl: "dorm_unity_build/HaksulUnityBuild.wasm",
+ });
+ const submitHandler = useCallback((e: Event) => {
+ const { detail } = e as CustomEvent<{ roomNum: string }>;
+ const { roomNum } = detail;
+ // setDormRoom(roomNum);
+
+ console.log(roomNum);
+ notice({ type: "SUCCESS", message: "기숙사 호실 입력 완료!" });
navigate("/phone-number");
- };
+ }, []);
+
+ useEffect(() => {
+ window.addEventListener("SendDormNumber", submitHandler);
+ return () => {
+ window.removeEventListener("SendDormNumber", submitHandler);
+ };
+ }, [window.addEventListener, window.removeEventListener, submitHandler]);
return (
-
- 기숙사 호실
-
- asdfjaskdlfjaskfasjdfklasd
-
+
+
+
+ 기숙사 호실
+
+
);
};
diff --git a/src/pages/email_page.module.scss b/src/pages/email_page.module.scss
index c05c34d..b73c12c 100644
--- a/src/pages/email_page.module.scss
+++ b/src/pages/email_page.module.scss
@@ -1,21 +1,3 @@
-.main {
- margin: 2rem auto;
- padding: 0 1rem;
- min-height: calc(100vh - 8rem);
- width: min(100%, 45rem);
-
- h1 {
- display: flex;
- align-items: center;
- gap: 1rem;
- margin-bottom: 2rem;
-
- img {
- width: 2rem;
- }
- }
-}
-
.down {
animation: slide-down 10s ease-in-out forwards;
}
@@ -87,16 +69,6 @@ section {
}
}
-.delete {
- margin-top: 2rem;
- padding: 1rem;
- width: 100%;
- &:hover {
- color: white;
- background-color: green;
- }
-}
-
.keyboard {
display: grid;
grid-template-columns: auto auto auto auto auto auto auto auto;
@@ -105,12 +77,21 @@ section {
button {
width: 100%;
height: 2em;
+ border-radius: 0.5rem;
}
button:hover {
color: white;
background-color: green;
}
- .clearbtn {
- width: 100%;
+}
+
+.delete {
+ margin-top: 2rem;
+ border-radius: 0.5rem;
+ padding: 1rem;
+ width: 100%;
+ &:hover {
+ color: white;
+ background-color: green;
}
}
diff --git a/src/pages/email_page.tsx b/src/pages/email_page.tsx
index 4dabbfb..e74793f 100644
--- a/src/pages/email_page.tsx
+++ b/src/pages/email_page.tsx
@@ -2,6 +2,112 @@ import { useContext, useEffect, useState } from "react";
import classes from "./email_page.module.scss";
import { useNavigate } from "react-router-dom";
import GlobalContext from "../components/context/context";
+import { useNotification } from "../components/notification/NotificationProvider";
+
+const json: any = require("../components/context/data.json");
+
+const original_3rd_grade_list = [
+ "강덕윤",
+ "강민후",
+ "강준호",
+ "강현민",
+ "공진",
+ "곽경욱",
+ "김경린",
+ "김규림",
+ "김규현",
+ "김동혁",
+ "김두영",
+ "김민구",
+ "김민규",
+ "김민석",
+ "김민재",
+ "김서호",
+ "김세현",
+ "김승연",
+ "김시우",
+ "김연준",
+ "김윤",
+ "김은수",
+ "김정헌",
+ "김주윤",
+ "김주한",
+ "김주해",
+ "김지원",
+ "김지한",
+ "김청아",
+ "김하루",
+ "김현민",
+ "김형원",
+ "노경민",
+ "라진우",
+ "문정원",
+ "문찬희",
+ "박건욱",
+ "박건희",
+ "박선용",
+ "박성현",
+ "박세웅",
+ "박세준",
+ "박승규",
+ "박연우",
+ "박종현",
+ "박종현",
+ "박준하",
+ "박준혁",
+ "박혜원",
+ "서명원",
+ "서윤아",
+ "송민준",
+ "송하엘",
+ "신주원",
+ "신주현",
+ "신희찬",
+ "안재형",
+ "오태양",
+ "오현택",
+ "우현욱",
+ "이동욱",
+ "이동혁",
+ "이명제",
+ "이상현",
+ "이서준",
+ "이성준",
+ "이세환",
+ "이승민",
+ "이윤수",
+ "이윤호",
+ "이재아",
+ "이종현",
+ "이주형",
+ "이한진",
+ "이현석",
+ "이형준",
+ "임휘묵",
+ "장서영",
+ "장연수",
+ "장차웅",
+ "전서한",
+ "정용환",
+ "정우영",
+ "정우재",
+ "정준상",
+ "정지훈",
+ "조민서",
+ "조민정",
+ "조민혁",
+ "차민재",
+ "최서원",
+ "최영빈",
+ "최정우",
+ "최진혁",
+ "최현규",
+ "한예원",
+ "함성준",
+ "홍세호",
+ "황보철준",
+ "황의찬",
+];
const shuffle = (str: string) =>
str
@@ -9,7 +115,7 @@ const shuffle = (str: string) =>
.sort(() => Math.random() - 0.5)
.join("");
-const shuffleTime = 20;
+const shuffleTime = 60;
const EmailPage = () => {
const [show, setShow] = useState(false);
@@ -27,6 +133,8 @@ const EmailPage = () => {
const navigate = useNavigate();
+ const notice = useNotification();
+
const type = (text: string) => {
if (text === "delete") {
setEmail("");
@@ -39,7 +147,7 @@ const EmailPage = () => {
setShow(true);
setTimeout(() => {
setIsDisabled(false);
- }, 1000);
+ }, 5000);
};
useEffect(() => {
@@ -57,14 +165,31 @@ const EmailPage = () => {
}, [setHangeul, setTimeLeft]);
const submitHandler = (_: any) => {
- console.log(savedText + email);
- console.log(studentNumber);
- clearInterval(intervalId);
- navigate("/dorm-room");
+
+ const num =
+ studentNumber[0] === "3"
+ ? original_3rd_grade_list.indexOf(json[studentNumber])
+ : Object.keys(json)
+ .filter((x) => x[0] === studentNumber[0])
+ .indexOf(studentNumber);
+
+ const correctEmail = `gbs.s2${(
+ 5 - parseInt(studentNumber[0])
+ ).toString()}00${(num + 1).toString().padStart(2, "0")}@ggh.goe.go.kr`;
+
+ console.log(correctEmail);
+
+ if (true) {
+ navigate("/dorm-room");
+ localStorage.setItem("email", correctEmail);
+ clearInterval(intervalId);
+ } else {
+ notice({ type: "ERROR", message: "그게 아닐 텐데" });
+ }
};
return (
-
+
Email
@@ -94,7 +219,9 @@ const EmailPage = () => {
- 문자에 마우스를 가져다 대면 글자가 입력됩니다!
+ 문자에 마우스를 가져다 대면 글자가 입력됩니다! gbs.s******@ggh.goe.go.kr
+ 형식으로 입력해 주세요!
+
개발자의 힌트: {timeLeft}초 안에 글자가 섞입니다!
+개발자의 게으름으로 인해 백스페이스 버튼이 없사오니 실수가 나면
diff --git a/src/pages/first_page.module.scss b/src/pages/first_page.module.scss
index a3967a9..dc51ee0 100644
--- a/src/pages/first_page.module.scss
+++ b/src/pages/first_page.module.scss
@@ -1,11 +1,9 @@
.index {
background-color: var(--main-color);
- padding: 4rem;
+ padding: 2rem 0;
main {
- margin: 2rem auto;
- padding: 0 1rem;
- min-height: calc(100vh - 8rem);
+ height: 100%;
width: min(100%, 45rem);
}
@@ -14,7 +12,35 @@
display: flex;
align-items: center;
flex-direction: column;
+ justify-content: center;
gap: 2rem;
+ padding-bottom: 2rem;
+
+ img {
+ width: 25%;
+ }
+
+ h1 {
+ span {
+ font-family: "Playfair Display";
+ font-weight: bold;
+ font-style: italic;
+ font-size: 2rem;
+ }
+
+ font-size: 2rem;
+ margin: 0;
+ }
+
+ .yakgwan {
+ font-size: 1.5rem;
+ font-weight: bold;
+ }
+
+ em {
+ // text-decoration: line-through;
+ font-weight: bold;
+ }
.control {
background-color: white;
@@ -27,28 +53,21 @@
align-items: center;
}
- .yakgwan {
- font-size: 1.25rem;
- }
-
- em {
- text-decoration: line-through;
- }
-
button {
background-color: var(--color-light);
}
- .underbar {
- text-decoration: underline;
+ .fakeclick {
+ font-weight: bold;
+
+ &:hover {
+ cursor: pointer;
+ text-decoration: underline;
+ }
}
.red {
color: red;
}
-
- img {
- width: 25%;
- }
}
}
diff --git a/src/pages/first_page.tsx b/src/pages/first_page.tsx
index 0900772..17ff28f 100644
--- a/src/pages/first_page.tsx
+++ b/src/pages/first_page.tsx
@@ -1,13 +1,10 @@
-import { useContext, useState } from "react";
+import { useState } from "react";
import classes from "./first_page.module.scss";
-import { useNavigate } from "react-router-dom";
-import GlobalContext from "../components/context/context";
+import FirstPageModal from "../components/first_page_modal";
const FirstPage = () => {
const [agree, setAgree] = useState(true);
- const navigate = useNavigate();
-
- const { activateTime } = useContext(GlobalContext);
+ const [show, setShow] = useState(false);
const checkboxClickHandler = (_: any) => {
setAgree(false);
@@ -16,52 +13,54 @@ const FirstPage = () => {
}, 500);
};
- const nextPageHandler = (_: any) => {
- activateTime();
- navigate("/student-number");
- };
-
return (
-
-
-
-
-
- SADA Interface
- [약관]
-
-
- 1. 해당 전화번호는 광고성 목적 으로 이용되며, 설문 작성일
- 이후로부터 1일 이내에 전화가 올 수 있습니다.
-
-
- 2. 설문에서 입력받은 모든 개인정보는 추첨 이외의 목적 으로
- 사용되며, 상업적 목적으로 이용 될 수 있습니다.{" "}
-
-
- 3. 1주일이 지나도 개인정보는
파기되지 않습니다.
+ <>
+
setShow(false)} />
+
+
+ 다음 페이지로 넘어가지 않기
+
+
+ setShow(true)}>여기
+ {"를 "}
+ 눌러 다음 페이지로
+ 넘어가세요
+
+
+
+
+ >
);
};
diff --git a/src/pages/last_page.module.scss b/src/pages/last_page.module.scss
index de786e3..86f60d0 100644
--- a/src/pages/last_page.module.scss
+++ b/src/pages/last_page.module.scss
@@ -1,12 +1,3 @@
-.list {
- display: flex;
- flex-direction: column;
- gap: 1rem;
- li {
- padding: 1rem;
- border-radius: 1rem;
- box-shadow: 0 0 1rem rgba(0, 0, 0, 0.05);
- display: flex;
- justify-content: space-between;
- }
+.id {
+ margin-bottom: 1rem;
}
diff --git a/src/pages/last_page.tsx b/src/pages/last_page.tsx
index 0b9d16d..c8577d9 100644
--- a/src/pages/last_page.tsx
+++ b/src/pages/last_page.tsx
@@ -1,41 +1,94 @@
+import { useContext, useEffect, useState } from "react";
import classes from "./last_page.module.scss";
+import GlobalContext from "../components/context/context";
+import { useNotification } from "../components/notification/NotificationProvider";
-const json: any = require("../components/context/score.json");
+const LastPage = () => {
+ const [id, setId] = useState("");
+ const { stopTime, goBack } = useContext(GlobalContext);
+ const [isSent, setIsSent] = useState(false);
-const sortDictionaryByValue = (dict: any) => {
- // Convert dictionary to an array of [key, value] pairs
- const items = Object.entries(dict);
+ const { studentNumber } = useContext(GlobalContext);
- // Sort the array based on the value
- items.sort((a, b) => (a[1] as number) - (b[1] as number));
- console.log(items);
+ const notice = useNotification();
- return items;
-};
+ useEffect(() => {
+ stopTime();
-const secondsToMMSS = (seconds: number) => {
- // Calculate the minutes and remaining seconds
- const minutes = Math.floor(seconds / 60);
- const remainingSeconds = seconds % 60;
+ return () => {
+ goBack();
+ };
+ }, [stopTime, goBack]);
- // Pad the remaining seconds with a leading zero if necessary
- const paddedSeconds = remainingSeconds.toString().padStart(2, "0");
+ const disable =
+ localStorage.getItem("phone-number") === null ||
+ localStorage.getItem("name") === null ||
+ localStorage.getItem("email") === null;
- // Return the formatted time
- return `${minutes}:${paddedSeconds}`;
-};
+ const submitHandler = async () => {
+ const time = localStorage.getItem("time");
+ const name = localStorage.getItem("name");
+ let phoneNumber = localStorage.getItem("phone-number");
+ const email = localStorage.getItem("email");
+
+ // console.log(phoneNumber);
+
+ phoneNumber = phoneNumber!.split("-").join("");
+
+ let reward;
+
+ if (parseInt(time!) >= 0 && parseInt(time!) <= 300) {
+ reward = 500;
+ } else if (parseInt(time!) > 300 && parseInt(time!) <= 600) {
+ reward = 400;
+ } else {
+ reward = 300;
+ }
+
+ if (studentNumber === "") {
+ console.log(
+ `https://sada.ziho.kr/coin/register?id=${id}&studentid=0&name=${name}&phone=${phoneNumber}&email=${email}`
+ );
+ fetch(
+ `https://sada.ziho.kr/coin/register?id=${id}&studentid=0&name=${name}&phone=${phoneNumber}&email=${email}`
+ )
+ .then(() => {
+ fetch(`https://sada.ziho.kr/coin/add/${id}/${name}/${reward}`);
+ notice({ type: "SUCCESS", message: "SADA코인 개설 완료!" });
+ setIsSent(true);
+ })
+ .catch(() => notice({ type: "ERROR", message: "SADA코인 개설 실패" }));
+ } else {
+ fetch(
+ `https://sada.ziho.kr/coin/register?id=${id}&studentid=${studentNumber}&name=${name}&phone=${phoneNumber}&email=${email}`
+ )
+ .then(() => {
+ fetch(`https://sada.ziho.kr/coin/add/${id}/${name}/${reward}`);
+ notice({ type: "SUCCESS", message: "SADA코인 개설 완료!" });
+ setIsSent(true);
+ })
+ .catch(() => notice({ type: "ERROR", message: "SADA코인 개설 실패" }));
+ }
+
+ localStorage.clear();
+ };
-const LastPage = () => {
return (
-
-
- {sortDictionaryByValue(Object(json)).map((item) => (
-
- {item[0]}
- {secondsToMMSS(item[1] as number)}
-
- ))}
-
+
+ setId(e.target.value)}
+ />
+
+ SADA코인 받기
+
);
};
diff --git a/src/pages/name_page.module.scss b/src/pages/name_page.module.scss
index 94f5f86..9228635 100644
--- a/src/pages/name_page.module.scss
+++ b/src/pages/name_page.module.scss
@@ -1,20 +1,38 @@
-section {
+.section {
position: relative;
- padding: 0 20%;
user-select: none;
.header {
- h2 {}
- input {}
- .description {}
+ .title {
+ display: flex;
+ justify-content: space-between;
+ gap: 0.5rem;
+ align-items: center;
+ margin-bottom: 1rem;
+
+ input {
+ width: 16rem;
+ font-size: 1.5rem;
+ }
+ :not(input) {
+ white-space: no-wrap;
+ word-break: break-all;
+ }
+
+ div {
+ display: flex;
+ gap: 1rem;
+ }
+ }
}
.nameTable {
position: relative;
width: 100%;
+ margin-top: 60px;
span {
position: absolute;
- animation: fall 1s ease-in forwards;
+ animation: fall 1.2s ease-in forwards;
font-size: 30px;
}
}
@@ -27,24 +45,36 @@ section {
position: fixed;
width: 120px;
height: 90px;
- bottom: 80px;
+ top: 660px;
img {
position: absolute;
width: 100%;
height: 100%;
+ z-index: 0;
+ }
+
+ div {
+ display: flex;
+ justify-content: center;
+
+ span {
+ font-size: 30px;
+ z-index: 1;
+ }
}
button {
position: absolute;
- width: 80%;
- height: 20%;
+ width: 60%;
+ height: 30%;
left: 50%;
- opacity: 70%;
+ opacity: 90%;
+ padding: 0;
}
.button1 {
- top: 35%;
+ top: 45%;
transform: translate(-50%, 50%);
}
@@ -54,6 +84,12 @@ section {
color: red;
}
}
+
+ .submit {
+ position: absolute;
+ top: 800px;
+ right: 0;
+ }
}
@keyframes fall {
diff --git a/src/pages/name_page.tsx b/src/pages/name_page.tsx
index 9c7b5f6..59801b2 100644
--- a/src/pages/name_page.tsx
+++ b/src/pages/name_page.tsx
@@ -1,8 +1,11 @@
import { useNavigate } from "react-router";
import classes from "./name_page.module.scss";
-import {useEffect, useState} from "react";
+import { useContext, useEffect, useState } from "react";
+import GlobalContext from "../components/context/context";
+import { useNotification } from "../components/notification/NotificationProvider";
+import { v4 } from "uuid";
-const DEBUG = true;
+const json: any = require("../components/context/data.json");
const nameChars = [
"가감갑강건겸경고공곽관교구국권",
@@ -14,101 +17,166 @@ const nameChars = [
"이인일임장재전정제조종주준지진",
"차찬창채천철청최태택하한함해허",
"헌혁현형혜호홍환황효후훈휘흔희",
-].join("").split(""); // 135 = 15 * 9 characters + 1
-
-function shuffle(array: any[]) {
- let currentIndex = array.length;
- while (currentIndex !== 0) {
- let randomIndex = Math.floor(Math.random() * currentIndex);
- currentIndex--;
- [array[currentIndex], array[randomIndex]] = [array[randomIndex], array[currentIndex]];
- }
- if (DEBUG) console.log(array.join(""));
- return array;
-}
+]
+ .join("")
+ .split(""); // 136 = 15 * 9 + 1
+
+const shuffle = (array: any[]) => {
+ let currentIndex = array.length;
+ while (currentIndex !== 0) {
+ let randomIndex = Math.floor(Math.random() * currentIndex);
+ currentIndex--;
+ [array[currentIndex], array[randomIndex]] = [
+ array[randomIndex],
+ array[currentIndex],
+ ];
+ }
+ return array;
+};
+
+const randomLeft = () =>
+ Math.random() * (window.innerWidth > 720 ? 720 : window.innerWidth);
interface Block {
- char: string;
- left: number;
+ char: string;
+ left: number;
+ id: string;
}
+export default function NamePage() {
+ const navigate = useNavigate();
+ const notice = useNotification();
+ const { studentNumber } = useContext(GlobalContext);
+ const [mouseX, setMouseX] = useState(window.innerWidth / 2);
+ const [basketChar, setBasketChar] = useState(null);
+ const [name, setName] = useState("");
+ const [blockList, setBlockList] = useState([]);
+ const [intervalId, setIntervalId] = useState | null>(null);
-export default function NamePage() {
- const navigate = useNavigate();
+ useEffect(() => {
+ const listener = (event: any) => setMouseX(event.clientX);
+
+ document.addEventListener("mousemove", listener);
- const submitHandler = () => {
- // Needs additional conditions
- navigate("/birthday");
+ return () => {
+ document.removeEventListener("mousemove", listener);
};
+ }, [studentNumber]);
- const [mouseX, setMouseX] = useState(window.innerWidth / 2);
- const [charQueue, setCharQueue] = useState(nameChars);
- const [newCharIndex, setNewCharIndex] = useState(0);
+ useEffect(() => {
+ if (studentNumber) {
+ const newList = shuffle(
+ shuffle(nameChars)
+ .slice(0, 60)
+ .concat(Array(5).fill(json[studentNumber].split("")).flat())
+ );
- const randomLeft = () => Math.random() * window.innerWidth * 0.6;
+ console.log(json[studentNumber]);
+ console.log(newList);
- const createNewBlock = (): Block => {
- if (newCharIndex >= charQueue.length)
- return {char: "", left: 0};
- const data = charQueue[newCharIndex];
- setNewCharIndex(newCharIndex + 1);
- return {char: data, left: randomLeft()};
- };
+ let index = 0;
+
+ setIntervalId(
+ setInterval(() => {
+ setBlockList((prev) => [
+ ...prev,
+ { char: newList[index], left: randomLeft(), id: v4() },
+ ]);
+ index = (index + 1) % newList.length;
+ }, 300)
+ );
+ }
+ }, [studentNumber]);
+
+ const submitHandler = () => {
+ if (name !== json[studentNumber]) {
+ notice({
+ type: "ERROR",
+ message: "학번과 이름이 안 맞네요~",
+ });
+ return;
+ }
+
+ clearInterval(intervalId!);
+
+ notice({
+ type: "SUCCESS",
+ message: "이름 쓰기 성공!",
+ });
+ localStorage.setItem("name", name);
+ navigate("/birthday");
+ };
- const [blockList, setBlockList] = useState([]);
-
- useEffect(() => {
- let ignore = false;
- if (!ignore) {
- if (DEBUG) console.log('load')
- setCharQueue(shuffle(nameChars));
- document.addEventListener('mousemove', event => setMouseX(event.clientX));
- }
- return () => {ignore = true;}
- }, []);
-
- useEffect(() => {
- const timeout = setTimeout(() => {
- const newBlock = createNewBlock();
- if (DEBUG) console.log(newCharIndex, charQueue, newBlock)
- if (newBlock.char !== "") setBlockList([...blockList, newBlock]);
- }, 300);
- }, [charQueue, newCharIndex]);
-
- return (
-
-
-
이름을 입력하세요
-
-
- 바구니에 글자를 담아보아요.
- 글자 순서는 상관없어요.
- 같은 글자는 두 번 다시 나타나지 않아요.
- 글자를 놓쳤다면... 안타까운 거죠
-
-
- 넘어가기
-
-
-
- {blockList.map(block => (
-
- {block.char}
-
- ))}
-
-
-
-
{
- }}>
- 입력
-
-
{
- }}>
- 버리기
-
-
-
- )
+ return (
+
+
+ 이름을 입력하세요
+
+
+
+ setName(name.slice(0, -1))}
+ >
+ Backspace
+
+
+
+
+ 자신의 이름에 포함된 글자를 바구니에 순서 상관없이 담아보아요!
+
+ 바구니에는 글자 하나만 넣을 수 있어요!
+
+ 바구니의 입력 버튼을 눌러 바구니에 담은 글자를 이름에 추가하세요!
+
+ 모든 글자를 추가하셨다면 '이름 글자 섞기' 버튼을 눌러 이름을 맞춰
+ 보세요!
+
+
+
+ {blockList.map((block) => (
+ {
+ const relativeDistance =
+ block.left -
+ mouseX +
+ 16 +
+ (window.innerWidth > 720 ? (window.innerWidth - 720) / 2 : 0);
+ if (relativeDistance >= -65 && relativeDistance <= 65) {
+ setBasketChar(block.char);
+ }
+ setBlockList((prev) => prev.filter((b) => b.id !== block.id));
+ }}
+ >
+ {block.char}
+
+ ))}
+
+
+
+
+ {basketChar !== null ? basketChar : "_"}
+
+
{
+ setName(name + basketChar);
+ setBasketChar(null);
+ }}
+ disabled={basketChar === null}
+ >
+ 입력
+
+
+
+ 넘어가기
+
+
+ );
}
diff --git a/src/pages/non_student/email_page.module.scss b/src/pages/non_student/email_page.module.scss
new file mode 100644
index 0000000..b73c12c
--- /dev/null
+++ b/src/pages/non_student/email_page.module.scss
@@ -0,0 +1,97 @@
+.down {
+ animation: slide-down 10s ease-in-out forwards;
+}
+
+.control {
+ margin-top: 1rem;
+ position: relative;
+ .first-layer {
+ position: absolute;
+ top: 0;
+ right: 0;
+ z-index: 10;
+ }
+
+ .second-layer {
+ position: absolute;
+ right: 0;
+ top: 0;
+ }
+}
+
+.text {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ background-color: var(--main-color);
+ color: white;
+ width: 100%;
+ font-size: 1.25rem;
+ border-radius: 1rem;
+ padding: 0.75rem 1rem;
+ box-shadow: 0 0 1rem rgba($color: #000000, $alpha: 0.1);
+
+ .highlight {
+ text-decoration: underline;
+ }
+
+ div {
+ display: flex;
+ gap: 0.5rem;
+ button {
+ background-color: white;
+ font-size: 1rem;
+ border-radius: 0.5rem;
+ padding: 0.3rem 0.6rem;
+ }
+ }
+}
+
+.time {
+ margin: 2rem 0;
+}
+
+section {
+ height: calc(100vh - 8rem);
+ position: relative;
+
+ input {
+ color: grey;
+ }
+}
+
+@keyframes slide-down {
+ 0% {
+ transform: translateY(0);
+ }
+ 100% {
+ transform: translateY(3rem);
+ }
+}
+
+.keyboard {
+ display: grid;
+ grid-template-columns: auto auto auto auto auto auto auto auto;
+ gap: 2rem;
+
+ button {
+ width: 100%;
+ height: 2em;
+ border-radius: 0.5rem;
+ }
+ button:hover {
+ color: white;
+ background-color: green;
+ }
+}
+
+.delete {
+ margin-top: 2rem;
+ border-radius: 0.5rem;
+ padding: 1rem;
+ width: 100%;
+ &:hover {
+ color: white;
+ background-color: green;
+ }
+}
diff --git a/src/pages/non_student/email_page.tsx b/src/pages/non_student/email_page.tsx
new file mode 100644
index 0000000..1d0abe3
--- /dev/null
+++ b/src/pages/non_student/email_page.tsx
@@ -0,0 +1,148 @@
+import { useEffect, useState } from "react";
+import classes from "./email_page.module.scss";
+import { useNavigate } from "react-router-dom";
+import { useNotification } from "../../components/notification/NotificationProvider";
+
+const validateEmail = (email: string) => {
+ return email.match(
+ /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/
+ );
+};
+
+const shuffle = (str: string) =>
+ str
+ .split("")
+ .sort(() => Math.random() - 0.5)
+ .join("");
+
+const shuffleTime = 60;
+
+const NonStudentEmailPage = () => {
+ const [show, setShow] = useState(false);
+ const [email, setEmail] = useState("");
+ const [isDisabled, setIsDisabled] = useState(true);
+ const [Hangeul, setHangeul] = useState(
+ "abcdefghijklmnopqrstuvwxyz1234567890!@#$%^&*().,"
+ );
+ const [intervalId, setIntervalId] =
+ useState>();
+ const [timeLeft, setTimeLeft] = useState(shuffleTime);
+ const [savedText, setSavedText] = useState("");
+
+ const navigate = useNavigate();
+
+ const notice = useNotification();
+
+ const type = (text: string) => {
+ if (text === "delete") {
+ setEmail("");
+ } else {
+ setEmail(email + text);
+ }
+ };
+
+ const clickhandler = (_: any) => {
+ setShow(true);
+ setTimeout(() => {
+ setIsDisabled(false);
+ }, 5000);
+ };
+
+ useEffect(() => {
+ setIntervalId(
+ setInterval(() => {
+ setTimeLeft((prevState) => {
+ if (prevState === 0) {
+ setHangeul((prev) => shuffle(prev));
+ return shuffleTime;
+ }
+ return prevState - 1;
+ });
+ }, 1000)
+ );
+ }, [setHangeul, setTimeLeft]);
+
+ const submitHandler = (_: any) => {
+ if (validateEmail(savedText + email)) {
+ navigate("../phone-number");
+ localStorage.setItem("email", savedText + email);
+ clearInterval(intervalId);
+ } else {
+ notice({ type: "ERROR", message: "올바른 이메일을 입력해주세요" });
+ }
+ };
+
+ return (
+
+
+
+ Email
+
+
+
+ 당신의 Email: {savedText}
+ {email}
+
+
+ {
+ setSavedText((prev) => prev + email);
+ setEmail("");
+ }}
+ >
+ 고정
+
+ {
+ setEmail(savedText + email);
+ setSavedText("");
+ }}
+ >
+ 고정 풀기
+
+
+
+
+ 문자에 마우스를 가져다 대면 글자가 입력됩니다!
+
+ 개발자의 힌트: {timeLeft}초 안에 글자가 섞입니다!
+
+ +개발자의 게으름으로 인해 백스페이스 버튼이 없사오니 실수가 나면
+ '지우기' 버튼을 통해 모든 텍스트를 지우셔야 합니다^^
+
+
+ {Hangeul.split("").map((e) => (
+ type(e)} key={e}>
+ {e}
+
+ ))}
+
+ type("delete")}
+ >
+ 지우기
+
+
+
+ 넘어가기
+
+
+ ㅋㅋㅋㅋ
+
+
+
+ );
+};
+
+export default NonStudentEmailPage;
diff --git a/src/pages/non_student/name_page.module.scss b/src/pages/non_student/name_page.module.scss
new file mode 100644
index 0000000..9228635
--- /dev/null
+++ b/src/pages/non_student/name_page.module.scss
@@ -0,0 +1,115 @@
+.section {
+ position: relative;
+ user-select: none;
+
+ .header {
+ .title {
+ display: flex;
+ justify-content: space-between;
+ gap: 0.5rem;
+ align-items: center;
+ margin-bottom: 1rem;
+
+ input {
+ width: 16rem;
+ font-size: 1.5rem;
+ }
+ :not(input) {
+ white-space: no-wrap;
+ word-break: break-all;
+ }
+
+ div {
+ display: flex;
+ gap: 1rem;
+ }
+ }
+ }
+
+ .nameTable {
+ position: relative;
+ width: 100%;
+ margin-top: 60px;
+ span {
+ position: absolute;
+ animation: fall 1.2s ease-in forwards;
+ font-size: 30px;
+ }
+ }
+
+ .line {
+ position: fixed;
+ }
+
+ .basket {
+ position: fixed;
+ width: 120px;
+ height: 90px;
+ top: 660px;
+
+ img {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ z-index: 0;
+ }
+
+ div {
+ display: flex;
+ justify-content: center;
+
+ span {
+ font-size: 30px;
+ z-index: 1;
+ }
+ }
+
+ button {
+ position: absolute;
+ width: 60%;
+ height: 30%;
+ left: 50%;
+ opacity: 90%;
+ padding: 0;
+ }
+
+ .button1 {
+ top: 45%;
+ transform: translate(-50%, 50%);
+ }
+
+ .button2 {
+ bottom: 30%;
+ transform: translate(-50%, 100%);
+ color: red;
+ }
+ }
+
+ .submit {
+ position: absolute;
+ top: 800px;
+ right: 0;
+ }
+}
+
+@keyframes fall {
+ 0% {
+ opacity: 1;
+ transform: translateY(0);
+ }
+
+ 10% {
+ opacity: 1;
+ transform: translateY(-10px);
+ }
+
+ 90% {
+ opacity: 1;
+ transform: translateY(400px);
+ }
+
+ 100% {
+ opacity: 0;
+ transform: translateY(400px);
+ }
+}
diff --git a/src/pages/non_student/name_page.tsx b/src/pages/non_student/name_page.tsx
new file mode 100644
index 0000000..6738429
--- /dev/null
+++ b/src/pages/non_student/name_page.tsx
@@ -0,0 +1,169 @@
+import { useNavigate } from "react-router";
+import classes from "./name_page.module.scss";
+import { useEffect, useState } from "react";
+import { useNotification } from "../../components/notification/NotificationProvider";
+import { v4 } from "uuid";
+
+import * as Hangul from "hangul-js";
+
+const nameChars = ["ㄱㄴㄷㄹㅁㅂㅅㅇㅈㅊㅋㅌㅍㅎ", "ㅏㅑㅓㅕㅗㅛㅜㅠㅡㅣ"]
+ .join("")
+ .split(""); // 136 = 15 * 9 + 1
+
+const shuffle = (array: any[]) => {
+ let currentIndex = array.length;
+ while (currentIndex !== 0) {
+ let randomIndex = Math.floor(Math.random() * currentIndex);
+ currentIndex--;
+ [array[currentIndex], array[randomIndex]] = [
+ array[randomIndex],
+ array[currentIndex],
+ ];
+ }
+ return array;
+};
+
+const randomLeft = () =>
+ Math.random() * (window.innerWidth > 720 ? 720 : window.innerWidth);
+
+interface Block {
+ char: string;
+ left: number;
+ id: string;
+}
+
+export default function NonStudentNamePage() {
+ const navigate = useNavigate();
+ const notice = useNotification();
+
+ const [mouseX, setMouseX] = useState(window.innerWidth / 2);
+ const [basketChar, setBasketChar] = useState(null);
+ const [name, setName] = useState("");
+ const [blockList, setBlockList] = useState([]);
+ const [intervalId, setIntervalId] = useState | null>(null);
+
+ useEffect(() => {
+ const listener = (event: any) => setMouseX(event.clientX);
+
+ document.addEventListener("mousemove", listener);
+
+ return () => {
+ document.removeEventListener("mousemove", listener);
+ };
+ }, []);
+
+ useEffect(() => {
+ const newList = shuffle(nameChars);
+
+ let index = 0;
+
+ setIntervalId(
+ setInterval(() => {
+ setBlockList((prev) => [
+ ...prev,
+ { char: newList[index], left: randomLeft(), id: v4() },
+ ]);
+ index = (index + 1) % newList.length;
+ }, 300)
+ );
+ }, []);
+
+ const submitHandler = () => {
+ clearInterval(intervalId!);
+
+ notice({
+ type: "SUCCESS",
+ message: "이름 쓰기 성공!",
+ });
+ localStorage.setItem("name", Hangul.assemble(name.split("")));
+ navigate("../birthday");
+ };
+
+ return (
+
+
+ 이름을 입력하세요
+
+
+
+ setName(name.slice(0, -1))}
+ >
+ Backspace
+
+ {
+ let newName = shuffle(
+ Hangul.assemble(name.split("")).split("")
+ ).join("");
+ while (Hangul.disassembleToString(newName) === name) {
+ newName = shuffle(
+ Hangul.assemble(name.split("")).split("")
+ ).join("");
+ }
+ setName(Hangul.disassembleToString(newName));
+ }}
+ >
+ 이름 글자 섞기
+
+
+
+
+ 자신의 이름에 포함된 글자를 바구니에 순서 상관없이 담아보아요!
+
+ 바구니에는 글자 하나만 넣을 수 있어요!
+
+ 바구니의 입력 버튼을 눌러 바구니에 담은 글자를 이름에 추가하세요!
+
+ 모든 글자를 추가하셨다면 '이름 글자 섞기' 버튼을 눌러 이름을 맞춰
+ 보세요!
+
+
+
+ {blockList.map((block) => (
+ {
+ const relativeDistance =
+ block.left -
+ mouseX +
+ 16 +
+ (window.innerWidth > 720 ? (window.innerWidth - 720) / 2 : 0);
+ if (relativeDistance >= -65 && relativeDistance <= 65) {
+ setBasketChar(block.char);
+ }
+ setBlockList((prev) => prev.filter((b) => b.id !== block.id));
+ }}
+ >
+ {block.char}
+
+ ))}
+
+
+
+
+ {basketChar !== null ? basketChar : "_"}
+
+
{
+ setName(name + basketChar);
+ setBasketChar(null);
+ }}
+ disabled={basketChar === null}
+ >
+ 입력
+
+
+
+ 넘어가기
+
+
+ );
+}
diff --git a/src/pages/phone_number_page.module.scss b/src/pages/phone_number_page.module.scss
new file mode 100644
index 0000000..1b3e711
--- /dev/null
+++ b/src/pages/phone_number_page.module.scss
@@ -0,0 +1,28 @@
+.main {
+ section {
+ height: 100%;
+ display: flex;
+ justify-content: space-between;
+ text {
+ font-size: 1rem;
+ }
+ .control {
+ display: flex;
+ justify-content: center;
+ button {
+ width: 3rem;
+ height: 3rem;
+ border-radius: 50%;
+ &:disabled {
+ background-color: grey;
+ color: white;
+ }
+ }
+ }
+ }
+ .submit {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ }
+}
diff --git a/src/pages/phone_number_page.tsx b/src/pages/phone_number_page.tsx
index 5822710..83663ec 100644
--- a/src/pages/phone_number_page.tsx
+++ b/src/pages/phone_number_page.tsx
@@ -1,25 +1,149 @@
-import { useContext } from "react";
-import GlobalContext from "../components/context/context";
-import { useNavigate } from "react-router";
+import classes from "./phone_number_page.module.scss";
+import { useState, useEffect } from "react";
+import { Knob } from "primereact/knob";
+import PhoneNumberModal from "../components/phone_number_modal";
-const PhoneNumberPage = () => {
- const { stopTime } = useContext(GlobalContext);
+const PhonePage = () => {
+ const [phoneNumber, setPhoneNumber] = useState("");
+ const [showModal, setShowModal] = useState(false);
+ const [value2, setValue2] = useState(0);
+ const [value3, setValue3] = useState(0);
+ const [disabledIncrementBtn2, setDisabledIncrementBtn2] = useState(false);
+ const [disabledIncrementBtn3, setDisabledIncrementBtn3] = useState(false);
- const navigate = useNavigate();
+ useEffect(() => {
+ const interval = setInterval(() => {
+ setValue2((v) => {
+ setDisabledIncrementBtn2(v === 9998);
+ return v > 0 ? v - 1 : 0;
+ });
+ setValue3((v) => {
+ setDisabledIncrementBtn3(v === 9998);
+ return v > 0 ? v - 1 : 0;
+ });
+ }, 1500);
+
+ return () => clearInterval(interval);
+ }, []);
+
+ const increment2 = () => {
+ setValue2(value2 + 1);
+ setDisabledIncrementBtn2(value2 === 9998);
+ };
+
+ const increment3 = () => {
+ setValue3(value3 + 1);
+ setDisabledIncrementBtn3(value3 === 9998);
+ };
const submitHandler = () => {
- stopTime();
- navigate("/last-page");
+ setShowModal(true);
+
+ setPhoneNumber(
+ "010-" +
+ "0".repeat(4 - value2.toString().length) +
+ value2 +
+ "-" +
+ "0".repeat(4 - value3.toString().length) +
+ value3
+ );
};
return (
-
- 전화번호
-
- asdf
-
-
+ <>
+ {
+ setShowModal(false);
+ }}
+ phoneNumber={phoneNumber}
+ />
+
+
+
+ 전화번호
+
+
+ 다이얼을 돌려 전화번호를 입력하세요!
+ 다이얼 속의 번호는 1.5초에 하나씩 자동으로 감소하고, 손으로
+ 다이얼을 돌려 전화번호와 유사하게 숫자를 맞추세요!
+ 다음 (+) 버튼으로 전화번호를 맞춰 정확한 순간 '넘어가기'
+ 버튼을 누르세요!
+
+
+ 친절하게도 첫 다이얼은 +82 10으로 맞춰져 있네요~
+
+
+
+
+
+
+
setValue2(e.value)}
+ />
+
+
+ +
+
+
+
+
+
+
+
+
+
setValue3(e.value)}
+ />
+
+
+ +
+
+
+
+
+
+
+ 이 번호를 바탕으로 선물이 전송될 예정이니 신중히 입력해 주세요~
+
+ 정확한 타이밍을 맞춰 버튼을 누르세요!
+
+ 넘어가기
+
+
+
+ >
);
};
-export default PhoneNumberPage;
+export default PhonePage;
diff --git a/src/pages/student_number_page.tsx b/src/pages/student_number_page.tsx
index 9aed0bb..b75d366 100644
--- a/src/pages/student_number_page.tsx
+++ b/src/pages/student_number_page.tsx
@@ -137,16 +137,17 @@ const StudentNumberPage = () => {
if (Object.keys(json).includes(number)) {
notice({
type: "SUCCESS",
- message: `축하합니다${number}!`,
+ message: `환영합니다!`,
});
setStudentNumber(number);
+ localStorage.setItem("studentNumber", number);
navigate("/name");
} else {
notice({
type: "SUCCESS",
- message: `${number}는 유효한 학번이 아닙니다~`,
+ message: `${number}(은/는) 유효한 학번이 아닙니다~`,
});
}
};