Skip to content

Commit 8ce3bc8

Browse files
committed
feat: 스피너 적용, 퀴즈 생성 및 수정화면 한글로 변경, 에러 모달 메시지 정리, 로그인 화면 버튼이름 변경 , 퀴즈 수정 구현 , sse 통신 구현
1 parent e542d8b commit 8ce3bc8

File tree

15 files changed

+131
-108
lines changed

15 files changed

+131
-108
lines changed

src/hooks/useApiMutation.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,7 @@ export function useApiMutation(mutationFn, options = {}) {
5151
const defaultOnError = (error) => {
5252
console.error("useMutation Error :", error);
5353
openConfirm({
54-
title: '데이터 처리중 오류가 발생했습니다.',
55-
html: error.response?.data?.message || "에러: 관리자에게 문의바랍니다."
54+
title: error.response?.data?.message || "에러: 관리자에게 문의바랍니다."
5655
});
5756
};
5857

src/hooks/useApiQuery.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,7 @@ export function useApiQuery(queryKey, queryFn, options = {}) {
4040
const defaultOnError = (error) => {
4141
console.error("useQuery Error :", error);
4242
openConfirm({
43-
title: '데이터를 불러오는 중 오류가 발생했습니다.',
44-
html: error.response?.data?.message || "에러: 관리자에게 문의바랍니다."
43+
title: error.response?.data?.message || "에러: 관리자에게 문의바랍니다."
4544
});
4645
};
4746

src/hooks/useRoomSseClient.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export default function useRoomSseClient(onRoomEvent) {
1414
useEffect(() => {
1515
if (eventSource) return;
1616

17-
eventSource = new EventSource(`${process.env.REACT_APP_API_BASE_URL}/sub/room.list`);
17+
eventSource = new EventSource(`${process.env.REACT_APP_API_BASE_URL}/sse/lobby`, {withCredentials: true});
1818

1919
eventSource.onopen = () => {
2020
console.log('✅ SSE 연결됨');
@@ -24,6 +24,7 @@ export default function useRoomSseClient(onRoomEvent) {
2424
eventSource.onmessage = (event) => {
2525
try {
2626
const payload = JSON.parse(event.data);
27+
console.log(event);
2728
onRoomEventRef.current?.(payload); // 예: { type: 'ROOM_CREATED', data: { ... } }
2829
} catch (e) {
2930
console.error('❌ SSE 메시지 파싱 실패', e);
@@ -32,8 +33,8 @@ export default function useRoomSseClient(onRoomEvent) {
3233

3334
eventSource.onerror = (err) => {
3435
console.error('❌ SSE 연결 오류:', err);
35-
eventSource.close();
36-
eventSource = null;
36+
// eventSource.close();
37+
// eventSource = null;
3738
setConnected(false);
3839
};
3940

src/pages/admin/UserList.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import TableBackGroundCard from "../../shared/TableBackGroundCard";
77
import {useApiQuery} from "../../hooks/useApiQuery";
88
import {useQueryParam} from "../../hooks/QueryParam";
99
import axios from "axios";
10+
import Spinner from "../../shared/Spinner";
1011

1112
const initColumns = [
1213
{ accessorKey: "id", header: "순번" },
@@ -24,7 +25,7 @@ const UserList = () => {
2425
const [searchTerm, setSearchTerm] = useState("");
2526
const [params, setParams] = useQueryParam();
2627
const [tableRows, setTableRows] = useState([]);
27-
const { data } = useApiQuery(
28+
const { data, isLoading, isFetching } = useApiQuery(
2829
['/admin/users', params], // queryKey에 params 포함
2930
() => usersRequest(params)
3031
);
@@ -55,6 +56,7 @@ const UserList = () => {
5556

5657
return (
5758
<div className="min-h-screen bg-gray-100 p-8">
59+
<Spinner show={isLoading || isFetching} />
5860
<div className="max-w-6xl mx-auto bg-white rounded-lg shadow-md border border-gray-200">
5961
{/* 헤더 및 검색 섹션 */}
6062
<div className="p-6 border-b border-gray-200 flex items-center justify-between">

src/pages/login/AdminLogin.js

Lines changed: 37 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import styles from "./Login.module.scss"
44
import {useState} from "react";
55
import {useApiMutation} from "../../hooks/useApiMutation";
66
import axios from "axios";
7+
import Spinner from "../../shared/Spinner";
78

89
const loginRequest = async ({ username, password }) => {
910
const params = new URLSearchParams();
@@ -27,7 +28,7 @@ const AdminLogin = () => {
2728
password: "",
2829
});
2930

30-
const { mutate: loginMutate } = useApiMutation(loginRequest, {
31+
const { mutate: loginMutate, isLoading } = useApiMutation(loginRequest, {
3132
onSuccess: () => {
3233
navigate("/room");
3334
},
@@ -47,41 +48,42 @@ const AdminLogin = () => {
4748
}
4849

4950
return (
50-
<div className={styles.loginContainer}>
51-
<div className={styles.loginCard}>
52-
<div className={styles.loginLogo}>
53-
<img src={mainLogo || "/placeholder.svg"} alt="뇌피셜 로고" className={styles.loginLogoImage} />
51+
<div className={styles.loginContainer}>
52+
<Spinner show={isLoading} />
53+
<div className={styles.loginCard}>
54+
<div className={styles.loginLogo}>
55+
<img src={mainLogo || "/placeholder.svg"} alt="뇌피셜 로고" className={styles.loginLogoImage} />
56+
</div>
57+
<form onSubmit={handleSubmit} className={styles.loginForm}>
58+
<div className={styles.inputGroup}>
59+
<input
60+
type="text"
61+
name="username"
62+
placeholder="아이디"
63+
value={loginData.username}
64+
onChange={handleInputChange}
65+
className={styles.loginInput}
66+
required
67+
/>
68+
</div>
69+
<div className={styles.inputGroup}>
70+
<input
71+
type="password"
72+
name="password"
73+
placeholder="비밀번호"
74+
value={loginData.password}
75+
onChange={handleInputChange}
76+
className={styles.loginInput}
77+
required
78+
/>
79+
</div>
80+
<button type="submit" className={styles.loginButton}>
81+
관리자 로그인
82+
</button>
83+
</form>
84+
</div>
5485
</div>
55-
<form onSubmit={handleSubmit} className={styles.loginForm}>
56-
<div className={styles.inputGroup}>
57-
<input
58-
type="text"
59-
name="username"
60-
placeholder="아이디"
61-
value={loginData.username}
62-
onChange={handleInputChange}
63-
className={styles.loginInput}
64-
required
65-
/>
66-
</div>
67-
<div className={styles.inputGroup}>
68-
<input
69-
type="password"
70-
name="password"
71-
placeholder="비밀번호"
72-
value={loginData.password}
73-
onChange={handleInputChange}
74-
className={styles.loginInput}
75-
required
76-
/>
77-
</div>
78-
<button type="submit" className={styles.loginButton}>
79-
관리자 로그인
80-
</button>
81-
</form>
82-
</div>
83-
</div>
84-
)
86+
)
8587
}
8688

8789
export default AdminLogin

src/pages/login/Login.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ import mainLogo from "../../assets/images/main-logo-rect.png"
33
import styles from "./Login.module.scss"
44

55
const Login = () => {
6-
const navigate = useNavigate()
7-
86
return (
97
<div className={styles.loginContainer}>
108
<div className={styles.loginCard}>
@@ -15,7 +13,7 @@ const Login = () => {
1513
onClick={() => {
1614
window.location.href = `${process.env.REACT_APP_API_BASE_URL}/oauth2/authorization/kakao`;
1715
}}>
18-
뇌피셜 입장하기
16+
뇌이싱 입장하기
1917
</button>
2018
</div>
2119
</div>

src/pages/login/NicknameForm.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
"use client"
2-
31
import { useState } from "react"
42
import styles from "./Login.module.scss"
53
import { isEmptyOrNull } from "../../utils/utils"
64
import axios from "axios";
75
import {useApiMutation} from "../../hooks/useApiMutation";
6+
import Spinner from "../../shared/Spinner";
87

98
const checkNicknameRequest = async (nickname) => {
109
const params = {
@@ -16,7 +15,7 @@ const checkNicknameRequest = async (nickname) => {
1615

1716
const NicknameForm = ({ nickname, setNickname, error, setError, setInputStatus }) => {
1817
const [isChecked, setChecked] = useState(false);
19-
const { mutate: checkNicknameMutate } = useApiMutation(checkNicknameRequest, {
18+
const { mutate: checkNicknameMutate, isLoading } = useApiMutation(checkNicknameRequest, {
2019
onSuccess: () => {
2120
setChecked(true);
2221
setInputStatus((prev) => ({ ...prev, nickname: true }));
@@ -54,6 +53,7 @@ const NicknameForm = ({ nickname, setNickname, error, setError, setInputStatus }
5453

5554
return (
5655
<div className={styles.formGroup}>
56+
<Spinner show={isLoading} />
5757
<label className={styles.formLabel} htmlFor="nickname">
5858
닉네임
5959
</label>

src/pages/login/Signup.js

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
"use client"
2-
31
import { useState } from "react"
42
import { useNavigate } from "react-router-dom"
53
import NicknameForm from "./NicknameForm"
64
import styles from "./Login.module.scss"
75
import axios from "axios";
86
import {useApiMutation} from "../../hooks/useApiMutation";
9-
import {useApiQuery} from "../../hooks/useApiQuery";
7+
import Spinner from "../../shared/Spinner";
108

119
const signupRequest = async (nickname) => {
1210
const params = {
@@ -25,10 +23,8 @@ const Signup = () => {
2523
nickname: false,
2624
});
2725
const navigate = useNavigate();
28-
const { mutate: signupMutate } = useApiMutation(signupRequest, {
29-
onSuccess: (data) => {
30-
console.log(data);
31-
// 회원가입 완료 후 방 목록으로 이동
26+
const { mutate: signupMutate, isLoading } = useApiMutation(signupRequest, {
27+
onSuccess: () => {
3228
navigate("/room");
3329
},
3430
});
@@ -48,6 +44,7 @@ const Signup = () => {
4844

4945
return (
5046
<div className={styles.signupContainer}>
47+
<Spinner show={isLoading} />
5148
<div className={styles.signupCard}>
5249
<div className={styles.signupHeader}>
5350
<h1 className={styles.signupTitle}>회원가입</h1>

src/pages/mypage/MyPage.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import axios from "axios";
77
import NicknameForm from "../login/NicknameForm";
88
import {useApiQuery} from "../../hooks/useApiQuery";
99
import {useApiMutation} from "../../hooks/useApiMutation";
10+
import Spinner from "../../shared/Spinner";
1011

1112
const userRequest = async () => {
1213
const response = await axios.get(`/user/me`);
@@ -34,11 +35,11 @@ const MyPage = () => {
3435
});
3536
const { openConfirm } = useConfirm();
3637
const navigate = useNavigate();
37-
const { data } = useApiQuery(
38+
const { data, isLoading } = useApiQuery(
3839
['/user/me'],
3940
() => userRequest()
4041
);
41-
const { mutate: userDeleteMutate } = useApiMutation(userDeleteRequest, {
42+
const { mutate: userDeleteMutate, isLoading: isUserDeleteLoading } = useApiMutation(userDeleteRequest, {
4243
onSuccess: () => {
4344
// 회원가입 완료 후 방 목록으로 이동
4445
navigate("/login");
@@ -83,6 +84,7 @@ const MyPage = () => {
8384

8485
return (
8586
<div className={styles.container}>
87+
<Spinner show={isLoading || isUserDeleteLoading} />
8688
<div className={styles.backgroundPattern}></div>
8789
<main className={styles.main}>
8890
<div className={styles.card}>

0 commit comments

Comments
 (0)