Skip to content

Commit 5f36644

Browse files
authored
Merge pull request #18 from danggin/feature/chat
♻️ refactor: 모달 리팩토링 - 키보드 이벤트 함수 memoization, UI 구조 리팩토링
2 parents fc2a4e4 + f1bfd20 commit 5f36644

13 files changed

Lines changed: 169 additions & 142 deletions

File tree

src/api/userAuthApi.ts

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ export interface ISignUpResponse {
2222
userNickname: string;
2323
}
2424

25+
export interface IEmailCheckResponse {
26+
available: boolean;
27+
}
28+
2529
export const loginUser = async (logInfo: {
2630
userEmail: string;
2731
password: string;
@@ -75,10 +79,30 @@ export const signUpUser = async (
7579
"Content-Type": "application/json",
7680
},
7781
});
78-
console.log(response);
7982
return response.data;
80-
} catch (err) {
81-
console.log(err);
83+
} catch (error) {
84+
console.log(error);
8285
throw new Error("회원가입에 실패했습니다.");
8386
}
8487
};
88+
89+
export const emailCheck = async (variables: {
90+
userEmail: string;
91+
}): Promise<IEmailCheckResponse> => {
92+
try {
93+
const response = await instance.post<IEmailCheckResponse>(
94+
"/user/email/check",
95+
variables,
96+
{
97+
withCredentials: true,
98+
headers: {
99+
"Content-Type": "application/json",
100+
},
101+
},
102+
);
103+
return response.data;
104+
} catch (error) {
105+
console.log(error);
106+
throw new Error("이메일 중복체크에 실패했습니다.");
107+
}
108+
};

src/components/form/Form.tsx

Lines changed: 0 additions & 27 deletions
This file was deleted.

src/components/ui/card/chatting/Chatting.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import * as S from "./ChattingStyle";
22
import ChatInputBox from "../../chatInput/ChatInputBox";
33

4-
export default function ChattingBox() {
4+
export default function ChattingBox({ socket }: { socket: any }) {
55
return (
66
<S.chat>
77
<S.chatInputBoxContainer>
8-
<ChatInputBox />
8+
<ChatInputBox socket={socket} />
99
</S.chatInputBoxContainer>
1010
</S.chat>
1111
);

src/components/ui/chatInput/ChatInputBox.tsx

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,17 @@
11
import Button from "../button/Button";
22
import * as S from "./chatInputStyle";
3-
import { useSocketStore } from "@store/useSocketStore";
43
import { useEffect } from "react";
54
// import { useParams } from "react-router-dom";
65

7-
export default function ChatInputBox() {
8-
const { socket } = useSocketStore();
9-
6+
export default function ChatInputBox({ socket }: { socket: any }) {
107
useEffect(() => {
118
if (!socket) {
129
console.error("Socket is not connected.");
1310
return;
1411
}
1512
}, []);
1613

17-
console.log("🚀 Socket:", socket);
14+
console.log("🚀 Socket: ", socket);
1815

1916
// const [message, setMessage] = useState("");
2017
// const params = useParams();

src/components/ui/modal/Modal.tsx

Lines changed: 20 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,53 @@
11
import ModalPortal from "./ModalPortal";
2-
import { useModalStore } from "../../../store/useModalStore";
2+
import { useModalStore } from "@store/useModalStore";
33
import { Inside, ModalFrame, Overlay } from "./modalStyle";
4-
import { useEffect } from "react";
4+
import { useEffect, useCallback, useRef } from "react";
55
import { useModal } from "@hooks/useModal";
66
import { modalComponents } from "./modalComponent";
77

88
export default function Modal() {
99
const { showModal, currentModal, modalColor } = useModalStore();
1010
const { closeModal } = useModal();
11+
const scrollYRef = useRef(0);
1112

12-
if (!showModal) return null;
13+
if (!showModal || !currentModal) return null;
1314

1415
useEffect(() => {
15-
document.body.style.cssText = `
16-
position: fixed;
17-
top: -${window.scrollY}px;
18-
overflow-y: scroll;
19-
width: 100%;`;
16+
scrollYRef.current = window.scrollY;
17+
document.body.style.overflow = "hidden";
18+
2019
return () => {
21-
const scrollY = document.body.style.top;
22-
document.body.style.cssText = "";
23-
window.scrollTo(0, parseInt(scrollY || "0", 10) * -1);
20+
document.body.style.overflow = "auto";
21+
window.scrollTo(0, scrollYRef.current);
2422
};
2523
}, []);
2624

27-
useEffect(() => {
28-
const onKeydownEscape = (e: KeyboardEvent) => {
29-
if (e.key === "Escape") {
30-
closeModal();
31-
}
32-
};
25+
const onKeydownEscape = useCallback(
26+
(e: KeyboardEvent) => {
27+
if (e.key === "Escape") closeModal();
28+
},
29+
[closeModal],
30+
);
3331

32+
useEffect(() => {
3433
document.addEventListener("keydown", onKeydownEscape);
3534

3635
return () => {
3736
document.removeEventListener("keydown", onKeydownEscape);
3837
};
39-
}, [closeModal]);
38+
}, [onKeydownEscape]);
4039

4140
return (
4241
<ModalPortal>
4342
<ModalFrame onClick={closeModal}>
44-
{modalColor === "white" ? (
45-
<Overlay onClick={closeModal}>
46-
<Inside onClick={(e) => e.stopPropagation()} styleKey={modalColor}>
47-
{currentModal ? modalComponents[currentModal] : null}
48-
</Inside>
49-
</Overlay>
50-
) : (
43+
<Overlay modalColor={modalColor}>
5144
<Inside
5245
onClick={(e) => e.stopPropagation()}
5346
styleKey={modalColor as "white" | "blue"}
5447
>
55-
{currentModal ? modalComponents[currentModal] : null}
48+
{modalComponents[currentModal]}
5649
</Inside>
57-
)}
50+
</Overlay>
5851
</ModalFrame>
5952
</ModalPortal>
6053
);

src/components/ui/modal/modalStyle.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,15 @@ export const ModalFrame = styled.div`
3333
inset: 0;
3434
`;
3535

36-
export const Overlay = styled.div`
36+
export const Overlay = styled.div<{ modalColor: string }>`
3737
display: flex;
3838
flex-direction: column;
3939
justify-content: center;
4040
align-items: center;
4141
width: 100%;
4242
height: 100%;
43-
background-color: rgba(0, 0, 0, 0.8);
43+
background-color: ${({ modalColor }) =>
44+
modalColor === "white" ? "rgba(0, 0, 0, 0.8)" : "rgba(255, 255, 255, 0)"};
4445
`;
4546

4647
export const Inside = styled.div<{ styleKey: keyof typeof modalStyles }>`

src/hooks/useMutation.tsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@ import {
77
outGameRoom,
88
} from "../api/gameRoomApi";
99
import {
10+
IEmailCheckResponse,
1011
ILoginResponse,
1112
ISignUpResponse,
1213
ISignUpVariables,
14+
emailCheck,
1315
loginUser,
1416
signUpUser,
1517
} from "../api/userAuthApi";
@@ -106,3 +108,17 @@ export const useSignUpSubmitMutation = () => {
106108
},
107109
});
108110
};
111+
112+
export const useEmailCheckSubmitMutation = () => {
113+
return useMutation<IEmailCheckResponse, Error, { userEmail: string }>(
114+
emailCheck,
115+
{
116+
onSuccess: (data) => {
117+
console.log(data);
118+
},
119+
onError: (error) => {
120+
console.log(error.message);
121+
},
122+
},
123+
);
124+
};

src/pages/game/GameRoom.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,7 @@ export default function GameRoom() {
389389
>
390390
상대 플레이어
391391
</OtherProfileCard>
392-
<ChattingBox />
392+
<ChattingBox socket={socket} />
393393
</S.leftContainer>
394394
<S.centerContainer>
395395
<S.otherPlayerDeck></S.otherPlayerDeck>

src/pages/user/signUp/SignUp.tsx

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import Form from "@components/form/Form";
21
import SignUpStep from "./SignUpStep";
32
import { useFunnel } from "@hooks/useFunnel";
43
import {
@@ -9,8 +8,9 @@ import {
98
StepBasic,
109
Stepper,
1110
} from "./SignUpStyle";
12-
import { SubmitHandler } from "react-hook-form";
13-
import { signUpSchema } from "./schema";
11+
import { FormProvider, useForm } from "react-hook-form";
12+
import { zodResolver } from "@hookform/resolvers/zod";
13+
import { signUpSchema, schema } from "./schema";
1414
import { useSignUpSubmitMutation } from "@hooks/useMutation";
1515
import { useNavigate } from "react-router-dom";
1616

@@ -20,6 +20,18 @@ export default function SignUp() {
2020
const { Funnel, Step, setStep, currentStep } = useFunnel(steps[0]);
2121
const mutation = useSignUpSubmitMutation();
2222
const navigate = useNavigate();
23+
const methods = useForm<signUpSchema>({
24+
resolver: zodResolver(schema),
25+
mode: "onBlur",
26+
shouldUnregister: true,
27+
defaultValues: {
28+
userEmail: "",
29+
password: "",
30+
passwordConfirm: "",
31+
userNickname: "",
32+
profileImage: [],
33+
},
34+
});
2335

2436
const nextClickHandler = (targetStep: string) => {
2537
setStep(targetStep);
@@ -29,10 +41,10 @@ export default function SignUp() {
2941
setStep(targetStep);
3042
};
3143

32-
const onSubmit: SubmitHandler<signUpSchema> = async (data) => {
44+
const onClickSubmit = async (data: signUpSchema) => {
3345
const { passwordConfirm, profileImage, ...formData } = data;
3446

35-
const result = mutation.mutate(formData);
47+
const result = await mutation.mutate(formData);
3648
console.log(result);
3749

3850
navigate("/user/signup/finish");
@@ -55,19 +67,8 @@ export default function SignUp() {
5567
</>
5668
)}
5769
</Stepper>
58-
<Form<FormData>
59-
onSubmit={onSubmit}
60-
formOptions={{
61-
defaultValues: {
62-
userEmail: "",
63-
password: "",
64-
passwordConfirm: "",
65-
userNickname: "",
66-
profileImage: [""],
67-
},
68-
}}
69-
>
70-
<FormWrapper>
70+
<FormProvider {...methods}>
71+
<FormWrapper onSubmit={methods.handleSubmit(onClickSubmit)}>
7172
<SignUpStep
7273
steps={steps}
7374
nextClickHandler={nextClickHandler}
@@ -76,7 +77,7 @@ export default function SignUp() {
7677
Step={Step}
7778
/>
7879
</FormWrapper>
79-
</Form>
80+
</FormProvider>
8081
</SignUpSection>
8182
</>
8283
);

src/pages/user/signUp/SignUpFinish.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { useNavigate } from "react-router-dom";
22
import heartImg from "../../../assets/images/icon_heart.svg";
33
import Button from "../../../components/ui/button/Button";
44

5-
import { HeartImage, Message, Welcome, Wrapper } from "./finishStyle";
5+
import { HeartImage, Message, Welcome, Wrapper } from "./SignUpFinishStyle";
66

77
export default function SignUpFinish() {
88
const navigate = useNavigate();

0 commit comments

Comments
 (0)