Files
XRLMS/app/login/page.tsx

258 lines
8.5 KiB
TypeScript
Raw Normal View History

2025-11-06 16:42:55 +09:00
"use client";
import Link from 'next/link';
2025-11-06 16:42:55 +09:00
import Image from 'next/image';
import { useState, useEffect } from 'react';
import { useRouter } from 'next/navigation';
import logo from '../logo.svg';
const checkIcon = "http://localhost:3845/assets/68720b08a673d8b68ae6482d642eeab286c9462b.svg";
type CheckboxProps = {
checked: boolean;
onChange: () => void;
label: string;
};
function Checkbox({ checked, onChange, label }: CheckboxProps) {
return (
<div className="flex items-center gap-2.5">
<button
type="button"
onClick={onChange}
className="relative w-[18px] h-[18px] rounded-[4px]"
>
{checked ? (
<>
<div className="absolute bg-[#515151] left-0 rounded-[4px] w-[18px] h-[18px] top-0" />
<div className="absolute left-[3px] w-3 h-3 top-[3px]">
<img alt="" className="block max-w-none w-full h-full" src={checkIcon} />
</div>
</>
) : (
<div className="absolute border border-[#b9b9b9] border-solid left-0 rounded-[4px] w-[18px] h-[18px] top-0" />
)}
</button>
<span className="text-sm text-[#515151] leading-[1.6]">{label}</span>
</div>
);
}
export default function LoginPage() {
2025-11-06 16:42:55 +09:00
const router = useRouter();
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const [rememberId, setRememberId] = useState(false);
const [autoLogin, setAutoLogin] = useState(false);
const [usernameError, setUsernameError] = useState('');
const [passwordError, setPasswordError] = useState('');
const [showErrorPopup, setShowErrorPopup] = useState(false);
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
setUsernameError('');
setPasswordError('');
// 아이디와 비밀번호가 비어있는지 확인
const isUsernameEmpty = !username.trim();
const isPasswordEmpty = !password.trim();
if (isUsernameEmpty) {
setUsernameError('이메일을 입력해 주세요.');
}
if (isPasswordEmpty) {
setPasswordError('비밀번호를 입력해 주세요.');
}
// 둘 중 하나라도 비어있으면 검증 중단
if (isUsernameEmpty || isPasswordEmpty) {
return;
}
// 아이디와 비밀번호 검증
if (username === 'qwre@naver.com' && password === '1234') {
2025-11-06 16:42:55 +09:00
// 로그인 성공
localStorage.setItem('isLoggedIn', 'true');
// 아이디 기억하기 체크 시 아이디 저장
if (rememberId) {
localStorage.setItem('rememberedUsername', username);
} else {
localStorage.removeItem('rememberedUsername');
}
// 루트 경로로 이동 (루트 페이지에서 로그인 상태를 확인하여 메인 페이지 표시)
window.location.href = '/';
} else {
// 로그인 실패 - 팝업 표시
setShowErrorPopup(true);
setUsernameError('아이디 또는 비밀번호가 올바르지 않습니다.');
setPasswordError('아이디 또는 비밀번호가 올바르지 않습니다.');
}
};
// 아이디 기억하기 기능 - 컴포넌트 마운트 시 저장된 아이디 불러오기
useEffect(() => {
const rememberedUsername = localStorage.getItem('rememberedUsername');
if (rememberedUsername) {
setUsername(rememberedUsername);
setRememberId(true);
}
}, []);
return (
2025-11-06 16:42:55 +09:00
<div className="min-h-screen flex justify-center relative pt-[178px]">
<div className="w-full max-w-md">
{/* 상단 로고 */}
<div className="mb-8 text-center">
2025-11-06 16:42:55 +09:00
<Image
src={logo}
alt="Logo"
width={179}
height={185}
className="mx-auto"
priority
/>
</div>
{/* 로그인 폼 */}
2025-11-06 16:42:55 +09:00
<form className="space-y-4" onSubmit={handleSubmit}>
{/* 아이디 입력폼 */}
2025-11-06 16:42:55 +09:00
<div className="flex flex-col gap-2">
<div className="flex flex-col gap-1">
<input
type="text"
id="username"
value={username}
onChange={(e) => {
setUsername(e.target.value);
setUsernameError('');
}}
className={`w-full px-4 py-2.5 border rounded-[8px] focus:outline-none ${usernameError
? 'border-[#e61a1a] border-solid'
: 'border-gray-300 focus:ring-2 focus:ring-blue-500'
}`}
placeholder="아이디(이메일)"
/>
{usernameError && (
<p className="text-[#e61a1a] text-xs leading-normal whitespace-pre">
{usernameError}
</p>
)}
</div>
</div>
{/* 비밀번호 입력폼 */}
2025-11-06 16:42:55 +09:00
<div className="flex flex-col gap-2">
<div className="flex flex-col gap-1">
<input
type="password"
id="password"
value={password}
onChange={(e) => {
setPassword(e.target.value);
setPasswordError('');
}}
className={`w-full px-4 py-2.5 border rounded-[8px] focus:outline-none ${passwordError
? 'border-[#e61a1a] border-solid'
: 'border-gray-300 focus:ring-2 focus:ring-blue-500'
}`}
placeholder="비밀번호를 입력하세요"
/>
{passwordError && (
<p className="text-[#e61a1a] text-xs leading-normal whitespace-pre">
{passwordError}
</p>
)}
</div>
</div>
{/* 체크박스 */}
2025-11-06 16:42:55 +09:00
<div className="flex items-center gap-[46px] justify-start">
<Checkbox
checked={rememberId}
onChange={() => setRememberId(!rememberId)}
label="아이디 기억하기"
/>
<Checkbox
checked={autoLogin}
onChange={() => setAutoLogin(!autoLogin)}
label="자동 로그인"
/>
</div>
{/* 로그인 버튼 */}
2025-11-06 16:42:55 +09:00
<div className="mt-[54px]">
<button
type="submit"
className="w-full h-[52px] bg-blue-500 text-white rounded-md hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500 flex items-center justify-center"
>
</button>
</div>
</form>
{/* 하단 링크 버튼들 */}
2025-11-06 16:42:55 +09:00
<div className="mt-4 flex items-center justify-center gap-2.5">
<Link
2025-11-06 19:27:27 +09:00
href="/register"
className="text-sm text-gray-600 hover:text-gray-800"
>
</Link>
2025-11-06 16:42:55 +09:00
<Image
src="/Divider.svg"
alt=""
width={1}
height={12}
className="h-3"
/>
2025-11-10 19:48:54 +09:00
<Link
href="/idfind"
className="text-sm text-gray-600 hover:text-gray-800"
>
2025-11-10 19:48:54 +09:00
</Link>
2025-11-06 16:42:55 +09:00
<Image
src="/Divider.svg"
alt=""
width={1}
height={12}
className="h-3"
/>
<button className="text-sm text-gray-600 hover:text-gray-800">
</button>
</div>
{/* 카피라이트 */}
2025-11-06 16:42:55 +09:00
<div className="absolute bottom-[40px] left-0 right-0 text-center text-sm text-gray-500">
© 2024 XR LMS. All rights reserved.
</div>
</div>
2025-11-06 16:42:55 +09:00
{/* 에러 팝업 */}
{showErrorPopup && (
<div className="fixed inset-0 flex items-center justify-center z-50">
<div className="bg-white rounded-[16px] shadow-[0px_4px_4px_0px_rgba(0,0,0,0.25)] max-w-md w-full mx-4">
<div className="flex flex-col gap-3 p-6">
<div className="text-sm text-black text-center leading-[1.6]">
<p className="mb-0"> .</p>
<p> .</p>
</div>
</div>
<div className="flex items-center w-full border-t border-gray-200">
<button
onClick={() => setShowErrorPopup(false)}
className="w-full h-12 text-sm text-[#404040] hover:bg-gray-50 focus:outline-none rounded-[16px]"
>
</button>
</div>
</div>
</div>
)}
</div>
);
}