Skip to content

Commit

Permalink
Refactor 자동저장, 사용자 인증 (Squash)
Browse files Browse the repository at this point in the history
Refactor 인증과 데이터 동기화 로직 분리

Refactor 불필요한 자동 저장 코드 제거

Refactor 자동 저장 지연 시간 상수화
  • Loading branch information
whoisrey committed Dec 17, 2024
1 parent a78902b commit 538d2bd
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 102 deletions.
55 changes: 46 additions & 9 deletions src/components/AuthPanel.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
import Modal from "./common/Modal";
import { toast } from "react-toastify";
import { GoogleAuthProvider, signInWithPopup } from "firebase/auth";
import auth from "../../firebase";

import googleLogo from "../assets/images/google-logo.svg";

import useUserAuth from "../hooks/useUserAuth";
import Modal from "./common/Modal";

import useUpdateData from "../hooks/useUpdateData";

import { loginUser, logoutUser } from "../services/authService";

import useAuthStore from "../stores/useAuthStore";
import useModalStore from "../stores/useModalStore";
import useDataStore from "../stores/useDataStore";

import {
AuthPanelContainer,
Expand All @@ -15,14 +22,44 @@ import {
} from "../style/AuthPanelStyle";

const AuthPanel = () => {
const { handleLogin, handleLogout } = useUserAuth();

const { isLoggedIn } = useAuthStore();
const { isLoggedIn, setIsLoggedIn } = useAuthStore();
const { setUserId, setUserData, setCurrentIndex } = useDataStore();
const { modals, closeModal } = useModalStore();

if (isLoggedIn === undefined) {
return null;
}
const handleLogin = async () => {
const provider = new GoogleAuthProvider();

try {
const result = await signInWithPopup(auth, provider);
const idToken = await result.user.getIdToken();

await loginUser(idToken);

setIsLoggedIn(true);
} catch (loginError) {
setIsLoggedIn(false);

toast.error("로그인을 다시 시도해주세요.");
console.error("로그인 에러가 발생하였습니다:", loginError);
}
};

const handleLogout = async () => {
try {
await logoutUser();
await auth.signOut();

setIsLoggedIn(false);
setUserId(null);
setUserData([]);
setCurrentIndex(0);
} catch (logoutError) {
toast.error("로그아웃을 다시 시도해주세요.");
console.error("로그아웃 에러가 발생하였습니다:", logoutError);
}
};

useUpdateData();

return (
<AuthPanelContainer data-testid="auth-panel">
Expand All @@ -42,7 +79,7 @@ const AuthPanel = () => {
{modals.errorModal && (
<Modal
modalName="errorModal"
firstButtonText="Back"
firstButtonText="뒤로"
handleFirstButton={() => closeModal("errorModal")}
$modalTestId="error-modal"
$firstButtonTestId="cancel-button"
Expand Down
3 changes: 3 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { Vector3, Euler } from "three";
import type { Vector3Values } from "./types/common";
import type { WallValues } from "./types/constants";

const AUTO_SAVE_DELAY = 5000;

const AUDIO_STARTING_POINT = 0;

const HAVE_NOTHING = 0;
Expand Down Expand Up @@ -65,6 +67,7 @@ const MEDIUM_LIGHT_INTENSITY = 0.5;
const HARD_LIGHT_INTENSITY = 1;

export {
AUTO_SAVE_DELAY,
AUDIO_STARTING_POINT,
HAVE_NOTHING,
HAVE_METADATA,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@ import { isDuplicateData } from "../utils/validators";

import type { UserData } from "../types/common";

const useAutoSavedPosition = (): null => {
const useAutoSavePosition = (delay: number): null => {
const timeoutRef = useRef(null);

const { isLoggedIn } = useAuthStore();
const { userId, userData, setUserData } = useDataStore();
const { modals } = useModalStore();
const { positions, rotations } = useModelStore();

const timeoutRef = useRef(null);
const isDuplicate = isDuplicateData(userData, positions, rotations);
const openSaveModal = modals.saveModal;

Expand All @@ -37,35 +38,40 @@ const useAutoSavedPosition = (): null => {
};

if (isLoggedIn) {
await saveUserPosition(userId, newUserData);
setUserData([...userData, newUserData]);
toast.success("자동 저장되었습니다!");
try {
setUserData([...userData, newUserData]);
await saveUserPosition(userId, newUserData);

toast.success("자동 저장되었습니다!");
} catch (error) {
console.error("서버에 저장을 실패하였습니다: ", error);
toast.error("서버에 저장을 실패하였습니다.");
}
} else {
localStorage.setItem(
"savedUserData",
JSON.stringify([...userData, newUserData]),
);
setUserData([...userData, newUserData]);
toast.success("자동 저장되었습니다!");
try {
localStorage.setItem(
"savedUserData",
JSON.stringify([...userData, newUserData]),
);
setUserData([...userData, newUserData]);

toast.success("자동 저장되었습니다!");
} catch (error) {
console.error("로컬 스토리지에 저장을 실패하였습니다: ", error);
toast.error("자동 저장을 실패하였습니다.");
}
}
};

useEffect(() => {
if (openSaveModal) {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
return;
}

if (!isDuplicate) {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}

timeoutRef.current = setTimeout(() => {
saveChanges();
}, 5000);
}, delay);
}

return () => {
Expand All @@ -78,4 +84,4 @@ const useAutoSavedPosition = (): null => {
return null;
};

export default useAutoSavedPosition;
export default useAutoSavePosition;
104 changes: 33 additions & 71 deletions src/hooks/useUserAuth.tsx → src/hooks/useUpdateData.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
import { useEffect } from "react";
import { toast } from "react-toastify";

import {
GoogleAuthProvider,
signInWithPopup,
onAuthStateChanged,
} from "firebase/auth";
import { onAuthStateChanged, User } from "firebase/auth";
import auth from "../../firebase";

import { loginUser, logoutUser } from "../services/authService";
import { getUserPosition, saveUserPosition } from "../services/userService";

import useAuthStore from "../stores/useAuthStore";
Expand All @@ -18,15 +12,26 @@ import { isSameData } from "../utils/validators";

import { UserData } from "../types/common";

const useUserAuth = () => {
const useUpdateData = (): null => {
const { setIsLoggedIn } = useAuthStore();
const { setUserId, setUserData, setCurrentIndex } = useDataStore();
const { setUserData, setCurrentIndex } = useDataStore();

const getLocalData = () => {
const savedData = localStorage.getItem("savedUserData");
return savedData ? JSON.parse(savedData) : [];
};

const updateLocalData = () => {
const savedLocalData = getLocalData();

if (savedLocalData.length > 0) {
setUserData(savedLocalData);
} else {
setUserData([]);
setCurrentIndex(0);
}
};

const filterUniqueData = (userData: UserData[], localData: UserData[]) => {
return localData.filter(
(local) => !userData.some((user) => isSameData(user, local)),
Expand All @@ -36,6 +41,7 @@ const useUserAuth = () => {
useEffect(() => {
const unsubscribe = onAuthStateChanged(auth, (user) => {
if (user) {
setIsLoggedIn(true);
updateUserData(user);
} else {
updateLocalData();
Expand All @@ -45,88 +51,44 @@ const useUserAuth = () => {
return () => unsubscribe();
}, []);

const updateUserData = async (user: any) => {
const updateUserData = async (user: User) => {
try {
const userId = user.uid;

const response = await getUserPosition();
const savedUserData = response.user;

setUserId(userId);
setIsLoggedIn(true);

const savedLocalData = getLocalData();

const uniqueData = filterUniqueData(savedUserData, savedLocalData).map(
(data) => ({
...data,
userId,
userId: user.uid,
}),
);
const mergedData = [...savedUserData, ...uniqueData];

setUserData(mergedData);

await Promise.all(
uniqueData.map((data) => saveUserPosition(userId, data)),
);

localStorage.removeItem("savedUserData");
} catch (error) {
setIsLoggedIn(false);

console.error(error);
}
};

const updateLocalData = () => {
const savedLocalData = getLocalData();

if (savedLocalData.length > 0) {
setUserData(savedLocalData);
} else {
setUserData([]);
setCurrentIndex(0);
}
};

const handleLogin = async () => {
const provider = new GoogleAuthProvider();
try {
await Promise.all(
uniqueData.map((data) => saveUserPosition(user.uid, data)),
);

try {
const result = await signInWithPopup(auth, provider);
const idToken = await result.user.getIdToken();

await loginUser(idToken);

setIsLoggedIn(true);
} catch (error) {
toast.error(
(error && error.message) || "알 수 없는 에러가 발생했습니다.",
);
}
};

const handleLogout = async () => {
try {
await logoutUser();
await auth.signOut();
localStorage.removeItem("savedUserData");
} catch (updateError) {
setUserData(savedUserData);

toast.error("동기화에 실패하였습니다.");
console.error("동기화에 실패하였습니다: ", updateError);
}
} catch (fetchError) {
setIsLoggedIn(false);
setUserId(null);
setUserData([]);
setCurrentIndex(0);
} catch (error) {
toast.error(
(error && error.message) || "알 수 없는 에러가 발생했습니다.",
);

toast.error("로그인을 다시 시도해주세요.");
console.error("데이터를 가져오는데 실패하였습니다:", fetchError);
}
};

return {
handleLogin,
handleLogout,
};
return null;
};

export default useUserAuth;
export default useUpdateData;
6 changes: 4 additions & 2 deletions src/pages/StudioPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { useState } from "react";
import { toast } from "react-toastify";
import { v4 as uuidv4 } from "uuid";

import { AUTO_SAVE_DELAY } from "../constants";

import Modal from "../components/common/Modal";
import NavHeader from "../components/common/NavHeader";
import Button from "../components/common/Button";
Expand All @@ -11,7 +13,7 @@ import Studio from "../components/Studio";
import ModeSwitch from "../components/Switch";
import UserInput from "../components/UserInput";

import useAutoSavedPosition from "../hooks/useAutoSavedPosition";
import useAutoSavePosition from "../hooks/useAutoSavePosition";
import useNavigateData from "../hooks/useNavigateData";
import useKeyboardEvent from "../hooks/useKeyboardEvent";

Expand Down Expand Up @@ -117,7 +119,7 @@ const StudioPage = () => {
setOpenGallery(false);
};

useAutoSavedPosition();
useAutoSavePosition(AUTO_SAVE_DELAY);
useNavigateData();
useKeyboardEvent();

Expand Down

0 comments on commit 538d2bd

Please sign in to comment.