diff --git a/apps/wr/public/images/bg_login.jpg b/apps/wr/public/images/bg_login.jpg new file mode 100644 index 000000000..b7793d16a Binary files /dev/null and b/apps/wr/public/images/bg_login.jpg differ diff --git a/apps/wr/src/entities/auth/lib/auth-wrapper.tsx b/apps/wr/src/entities/auth/lib/auth-wrapper.tsx index dcc6e81cd..9b59774fc 100644 --- a/apps/wr/src/entities/auth/lib/auth-wrapper.tsx +++ b/apps/wr/src/entities/auth/lib/auth-wrapper.tsx @@ -1,7 +1,8 @@ "use client"; import { useEffect } from "react"; -import { useRouter, usePathname } from "next/navigation"; +import { useRouter } from "next/navigation"; +import { usePathname } from "next/navigation"; import { client } from "../../../shared/api"; import type { IUserInfo } from "../../../shared/store"; import { useUserStore } from "../../../shared/lib"; @@ -42,16 +43,17 @@ const AuthWrapper = ({ children }: { children: React.ReactNode }) => { } catch (refreshError) { console.error("Token refresh failed:", refreshError); setUserInfo(null); - + const hostname = window.location.hostname; // 개발 환경에서는 localhost 도메인 사용 if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "con.mind-one.co.kr") - router.push("/"); // 개발시 홈으로 돌아가기 + router.push("/auth/login"); // 운영 환경에서는 서브도메인을 포함한 최상위 도메인 사용 // router.push는 같은 Next.js 앱 내에서만 작동하므로 다른 앱으로 이동할 때는 window.location.href 사용 - if (hostname.includes("hasuon.or.kr")) window.location.href = LOGIN_PAGE_URL; // 세션 만료 시 CM 로그인 페이지로 리다이렉트 + if (hostname.includes("hasuon.or.kr")) + window.location.href = LOGIN_PAGE_URL; // 세션 만료 시 CM 로그인 페이지로 리다이렉트 } } })(); diff --git a/apps/wr/src/features/auth/login/ui/login-page.tsx b/apps/wr/src/features/auth/login/ui/login-page.tsx index db3a72ffd..7e57b0f20 100644 --- a/apps/wr/src/features/auth/login/ui/login-page.tsx +++ b/apps/wr/src/features/auth/login/ui/login-page.tsx @@ -1,321 +1,130 @@ "use client"; -import { useState, useEffect } from "react"; import Image from "next/image"; import { images } from "@common/assets"; import { LoginApi } from "@/src/entities/auth"; -import { ENDPOINT } from "@/src/shared/config"; -import OtpModal from "./OtpModal"; -import TwoFAModal from "./TwoFAModal"; -import UserSignupModal from "./UserSignupModal"; import "./login.css"; -import { useRouter } from "next/navigation"; function LoginPage() { - const [isOtpEnabled, setIsOtpEnabled] = useState(false); - const [showOtpModal, setShowOtpModal] = useState(false); - const [showTwoFAModal, setShowTwoFAModal] = useState(false); - const [showSignupModal, setShowSignupModal] = useState(false); - const [isLoading, setIsLoading] = useState(false); - const [error, setError] = useState(""); - const [successMessage, setSuccessMessage] = useState(""); - const router = useRouter(); - - // 모달 상태 디버깅 - useEffect(() => { - console.log("Modal states - OTP:", showOtpModal, "2FA:", showTwoFAModal); - }, [showOtpModal, showTwoFAModal]); - const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); - setIsLoading(true); - setError(""); - setSuccessMessage(""); - try { - const formData = new FormData(e.target as HTMLFormElement); - const userId = formData.get("id") as string; - const password = formData.get("password") as string; + const formData = new FormData(e.target as HTMLFormElement); + const userId = formData.get("id") as string; + const password = formData.get("password") as string; - console.log("Login attempt - OTP enabled:", isOtpEnabled); - console.log("User ID:", userId); - - if (isOtpEnabled) { - // 2FA 로그인 - Proxy를 통해 처리 (2FA 전용 엔드포인트 사용) - console.log("Starting 2FA login..."); - - const response = await fetch(`/api/proxy${ENDPOINT.USER_SERVICE.LOGIN_2FA}`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - userId, - password, - provider: 'password' - }), - }); - - if (!response.ok) { - const errorData = await response.json(); - let errorMsg = errorData.message || '로그인 실패'; - if (Array.isArray(errorData.errors) && errorData.errors.length > 0) { - errorMsg = errorData.errors.map((e: { message: string }) => e.message).join(', '); - } - throw new Error(errorMsg); - } - - const data = await response.json(); - console.log("2FA login response:", data); - console.log("Response headers:", Object.fromEntries(response.headers.entries())); - - // 2FA 로그인 응답에는 tempToken과 registered2FA만 포함됨 - if (!data.tempToken) { - throw new Error("Missing tempToken in 2FA login response"); - } - - // 임시 토큰을 localStorage에 저장 (OTP 인증용) - localStorage.setItem('tempToken', data.tempToken); - console.log("tempToken saved:", data.tempToken); - - if (data.registered2FA) { - console.log("User has 2FA registered, showing OTP modal"); - setShowOtpModal(true); - } else { - console.log("User doesn't have 2FA registered, showing 2FA setup modal"); - setShowTwoFAModal(true); - } - } else { - // 기본 로그인 - proxy를 통해 처리 - console.log("Starting basic login..."); - await LoginApi.login({ userId, password }); - window.location.href = "/map/mainMap"; - } - } catch (error: unknown) { - console.error("Login error:", error); - - // 에러 처리 - if (error instanceof Error) { - setError(error.message); - } else { - setError("로그인에 실패했습니다. 아이디와 비밀번호를 확인해주세요."); - } - } finally { - setIsLoading(false); - } - }; - - const handleOtpSuccess = () => { - console.log("OTP authentication successful, redirecting to dashboard"); - localStorage.removeItem("tempToken"); // 임시 토큰 제거 - router.push("/dashboard"); - }; - - const handleTwoFASuccess = () => { - console.log("2FA setup successful, redirecting to dashboard"); - localStorage.removeItem("tempToken"); // 임시 토큰 제거 - router.push("/dashboard"); - }; - - const handleOtpClose = () => { - console.log("OTP modal closed"); - setShowOtpModal(false); - localStorage.removeItem("tempToken"); - }; - - const handleTwoFAClose = () => { - console.log("2FA modal closed"); - setShowTwoFAModal(false); - localStorage.removeItem("tempToken"); - }; - - const handleSignupSuccess = () => { - console.log("회원가입 성공"); - setError(""); // 에러 메시지 초기화 - setSuccessMessage("회원가입이 완료되었습니다. 로그인해주세요."); - }; - - const handleSignupClose = () => { - console.log("회원가입 모달 닫기"); - setShowSignupModal(false); - setSuccessMessage(""); // 성공 메시지 초기화 + await LoginApi.login({ userId, password }); + window.location.href = "/map/mainMap"; }; return ( - <> -
-
-
-

- 유역하수도 통합플랫폼 -
- 통합관리시스템 -

-

유역하수도 통합플랫폼에 오신 것을 환영합니다.

+
+
+
+

+ 하수도정보시스템 +
+ CMS 통합관리시스템 +

+

하수도정보시스템 CMS 통합관리시스템에 오신 것을 환영합니다.

+
+
+ logo +
+
+
+
+
    +
  • +

    ID

    +
    + + +
    +
  • +
  • +

    PASSWORD

    +
    + + +
    +
  • +
+ -
- logo + +
+
+

copyright © 2023 KECO. All rights reserved.

+
+ +

+ + 주소 : (22689) 인천광역시 서구 환경로 42(경서동 + 종합환경연구단지) + + + 전화 : (시스템) 032-590-4321, 3752, 4314 / (통 계) 032-590-3723, + 3722 + + 팩스 :032-590-3729 +

- -
-
    -
  • -

    ID

    -
    - - -
    -
  • -
  • -

    PASSWORD

    -
    - - -
    -
  • -
-
-
- - -
-
- setIsOtpEnabled(e.target.checked)} - disabled={isLoading} - /> - -
-
- - {error && ( -
- {error} -
- )} - {successMessage && ( -
- {successMessage} -
- )} -
- 계정이 없으신가요? - -
-
-
-

copyright © 2023 KECO. All rights reserved.

-
- -

- - 주소 : (22689) 인천광역시 서구 환경로 42(경서동 - 종합환경연구단지) - - - 전화 : (시스템) 032-590-4321, 3752, 4314 / (통 계) 032-590-3723, - 3722 - - 팩스 :032-590-3729 -

-
-
- -
- - {/* OTP 인증 모달 */} - - - {/* 2FA 등록 모달 */} - - - {/* 회원가입 모달 */} - - + +
); } export { LoginPage }; +