1b7842c305
- Added new API endpoints for retrieving company-specific user lists and sending immediate logs for selected users. - Enhanced the smartFactoryLogController with functions to handle user retrieval and immediate log sending, improving operational efficiency. - Updated adminRoutes to include routes for the new functionalities, ensuring proper access control for super admins. - Refactored the sendSmartFactoryLog function to improve logging and error handling, providing better insights into the log transmission process. These changes aim to enhance the smart factory log management capabilities, facilitating better user interaction and operational tracking.
179 lines
4.9 KiB
TypeScript
179 lines
4.9 KiB
TypeScript
"use client";
|
|
|
|
import { useState, useEffect, useCallback } from "react";
|
|
import { useRouter } from "next/navigation";
|
|
import { LoginFormData } from "@/types/auth";
|
|
import { AUTH_CONFIG, FORM_VALIDATION } from "@/constants/auth";
|
|
import { apiCall } from "@/lib/api/client";
|
|
|
|
/**
|
|
* 로그인 관련 비즈니스 로직을 관리하는 커스텀 훅
|
|
* API 호출은 lib/api/client의 apiCall(Axios) 사용 (fetch 직접 사용 금지)
|
|
*/
|
|
export const useLogin = () => {
|
|
const router = useRouter();
|
|
|
|
// 상태 관리
|
|
const [formData, setFormData] = useState<LoginFormData>({
|
|
userId: "",
|
|
password: "",
|
|
});
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
const [error, setError] = useState("");
|
|
const [showPassword, setShowPassword] = useState(false);
|
|
const [isPopMode, setIsPopMode] = useState(false);
|
|
|
|
// localStorage에서 POP 모드 상태 복원
|
|
useEffect(() => {
|
|
const saved = localStorage.getItem("popLoginMode");
|
|
if (saved === "true") setIsPopMode(true);
|
|
}, []);
|
|
|
|
const togglePopMode = useCallback(() => {
|
|
setIsPopMode((prev) => {
|
|
const next = !prev;
|
|
localStorage.setItem("popLoginMode", String(next));
|
|
return next;
|
|
});
|
|
}, []);
|
|
|
|
/**
|
|
* 폼 입력값 변경 처리
|
|
*/
|
|
const handleInputChange = useCallback(
|
|
(e: React.ChangeEvent<HTMLInputElement>) => {
|
|
const { name, value } = e.target;
|
|
setFormData((prev) => ({
|
|
...prev,
|
|
[name]: value,
|
|
}));
|
|
// 입력 시 에러 메시지 제거
|
|
if (error) setError("");
|
|
},
|
|
[error],
|
|
);
|
|
|
|
/**
|
|
* 비밀번호 표시/숨김 토글
|
|
*/
|
|
const togglePasswordVisibility = useCallback(() => {
|
|
setShowPassword((prev) => !prev);
|
|
}, []);
|
|
|
|
/**
|
|
* 입력값 검증
|
|
*/
|
|
const validateForm = useCallback((): string | null => {
|
|
if (!formData.userId.trim()) {
|
|
return FORM_VALIDATION.MESSAGES.USER_ID_REQUIRED;
|
|
}
|
|
if (!formData.password.trim()) {
|
|
return FORM_VALIDATION.MESSAGES.PASSWORD_REQUIRED;
|
|
}
|
|
return null;
|
|
}, [formData]);
|
|
|
|
/**
|
|
* 기존 인증 상태 확인 (apiCall 사용)
|
|
*/
|
|
const checkExistingAuth = useCallback(async () => {
|
|
try {
|
|
const token = localStorage.getItem("authToken");
|
|
if (!token) return;
|
|
|
|
const result = await apiCall<{ isAuthenticated?: boolean }>("GET", AUTH_CONFIG.ENDPOINTS.STATUS);
|
|
|
|
if (result.success && result.data?.isAuthenticated) {
|
|
router.push(AUTH_CONFIG.ROUTES.MAIN);
|
|
} else {
|
|
localStorage.removeItem("authToken");
|
|
document.cookie = "authToken=; path=/; max-age=0; SameSite=Lax";
|
|
}
|
|
} catch {
|
|
localStorage.removeItem("authToken");
|
|
document.cookie = "authToken=; path=/; max-age=0; SameSite=Lax";
|
|
}
|
|
}, [router]);
|
|
|
|
/**
|
|
* 로그인 처리 (apiCall 사용 - Axios 기반, fetch 미사용)
|
|
*/
|
|
const handleLogin = useCallback(
|
|
async (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
|
|
const validationError = validateForm();
|
|
if (validationError) {
|
|
setError(validationError);
|
|
return;
|
|
}
|
|
|
|
setIsLoading(true);
|
|
setError("");
|
|
|
|
try {
|
|
const result = await apiCall<{
|
|
token?: string;
|
|
firstMenuPath?: string;
|
|
firstMenuName?: string;
|
|
popLandingPath?: string;
|
|
}>("POST", AUTH_CONFIG.ENDPOINTS.LOGIN, {
|
|
userId: formData.userId,
|
|
password: formData.password,
|
|
});
|
|
|
|
if (result.success && result.data?.token) {
|
|
// JWT 토큰 저장 (localStorage와 쿠키 모두에 저장)
|
|
localStorage.setItem("authToken", result.data.token);
|
|
|
|
// 쿠키에도 저장 (미들웨어에서 사용)
|
|
document.cookie = `authToken=${result.data.token}; path=/; max-age=86400; SameSite=Lax`;
|
|
|
|
if (isPopMode) {
|
|
const popPath = result.data?.popLandingPath;
|
|
if (popPath) {
|
|
router.push(popPath);
|
|
} else {
|
|
setError("POP 화면이 설정되어 있지 않습니다. 관리자에게 메뉴 관리에서 POP 화면을 설정해달라고 요청하세요.");
|
|
setIsLoading(false);
|
|
return;
|
|
}
|
|
} else {
|
|
router.push(AUTH_CONFIG.ROUTES.MAIN);
|
|
}
|
|
} else {
|
|
// 로그인 실패
|
|
setError(result.message || FORM_VALIDATION.MESSAGES.LOGIN_FAILED);
|
|
console.error("로그인 실패:", result);
|
|
}
|
|
} catch (error) {
|
|
console.error("로그인 오류:", error);
|
|
setError(FORM_VALIDATION.MESSAGES.CONNECTION_FAILED);
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
},
|
|
[formData, validateForm, router, isPopMode],
|
|
);
|
|
|
|
// 컴포넌트 마운트 시 기존 인증 상태 확인
|
|
useEffect(() => {
|
|
checkExistingAuth();
|
|
}, [checkExistingAuth]);
|
|
|
|
return {
|
|
// 상태
|
|
formData,
|
|
isLoading,
|
|
error,
|
|
showPassword,
|
|
isPopMode,
|
|
|
|
// 액션
|
|
handleInputChange,
|
|
handleLogin,
|
|
togglePasswordVisibility,
|
|
togglePopMode,
|
|
};
|
|
};
|