Headless Login 데모 앱 초기 구현 및 Mock API 구축
This commit is contained in:
116
public/app.js
Normal file
116
public/app.js
Normal file
@@ -0,0 +1,116 @@
|
||||
const identifierInput = document.getElementById('identifier');
|
||||
const passwordField = document.getElementById('password-field');
|
||||
const passwordInput = document.getElementById('password');
|
||||
const inputHint = document.getElementById('input-hint');
|
||||
const submitButton = document.getElementById('submit-button');
|
||||
const loginForm = document.getElementById('login-form');
|
||||
const statusText = document.getElementById('status-text');
|
||||
const statusDisplay = document.getElementById('status-display');
|
||||
const successPanel = document.getElementById('success-panel');
|
||||
const successTitle = document.getElementById('success-title');
|
||||
const successDescription = document.getElementById('success-description');
|
||||
|
||||
let currentMode = 'unknown'; // 'unknown', 'phone', 'employee'
|
||||
|
||||
function classifyInput(value) {
|
||||
const trimmed = value.trim();
|
||||
if (!trimmed) return 'unknown';
|
||||
|
||||
// Check if it's strictly numeric (ignoring spaces or dashes for phone)
|
||||
const numericOnly = trimmed.replace(/[\s-]/g, '');
|
||||
if (/^\d+$/.test(numericOnly)) {
|
||||
return 'phone';
|
||||
}
|
||||
return 'employee';
|
||||
}
|
||||
|
||||
function formatPhoneNumber(value) {
|
||||
const digits = value.replace(/\D/g, '').slice(0, 11);
|
||||
if (digits.length <= 3) return digits;
|
||||
if (digits.length <= 7) return `${digits.slice(0, 3)}-${digits.slice(3)}`;
|
||||
return `${digits.slice(0, 3)}-${digits.slice(3, 7)}-${digits.slice(7)}`;
|
||||
}
|
||||
|
||||
function updateUI() {
|
||||
const value = identifierInput.value;
|
||||
const mode = classifyInput(value);
|
||||
currentMode = mode;
|
||||
|
||||
if (mode === 'phone') {
|
||||
const formatted = formatPhoneNumber(value);
|
||||
if (identifierInput.value !== formatted) {
|
||||
identifierInput.value = formatted;
|
||||
}
|
||||
|
||||
passwordField.classList.add('hidden');
|
||||
inputHint.textContent = '전화번호가 확인되었습니다. 인증링크 발송 흐름을 사용할 수 있습니다.';
|
||||
submitButton.textContent = '인증링크 발송';
|
||||
submitButton.disabled = value.replace(/\D/g, '').length < 10;
|
||||
statusText.textContent = '인증링크 발송 단계를 준비했습니다.';
|
||||
} else if (mode === 'employee') {
|
||||
passwordField.classList.remove('hidden');
|
||||
inputHint.textContent = 'ID 입력이 확인되었습니다. 비밀번호를 입력해 로그인하세요.';
|
||||
submitButton.textContent = '로그인';
|
||||
submitButton.disabled = passwordInput.value.trim().length === 0;
|
||||
statusText.textContent = '비밀번호 입력 단계를 노출했습니다.';
|
||||
} else {
|
||||
passwordField.classList.add('hidden');
|
||||
inputHint.textContent = '입력값에 따라 적절한 로그인 방식이 자동으로 선택됩니다.';
|
||||
submitButton.textContent = '로그인';
|
||||
submitButton.disabled = true;
|
||||
statusText.textContent = '입력값을 기다리는 초기 상태입니다.';
|
||||
}
|
||||
}
|
||||
|
||||
identifierInput.addEventListener('input', updateUI);
|
||||
passwordInput.addEventListener('input', updateUI);
|
||||
|
||||
loginForm.addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
const identifier = identifierInput.value;
|
||||
const password = passwordInput.value;
|
||||
|
||||
submitButton.disabled = true;
|
||||
const originalBtnText = submitButton.textContent;
|
||||
submitButton.textContent = '처리 중...';
|
||||
|
||||
try {
|
||||
let response;
|
||||
if (currentMode === 'phone') {
|
||||
response = await fetch('/api/send-link', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ phoneNumber: identifier.replace(/\D/g, '') })
|
||||
});
|
||||
} else {
|
||||
response = await fetch('/api/login', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ loginId: identifier, password: password })
|
||||
});
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok) {
|
||||
loginForm.classList.add('hidden');
|
||||
statusDisplay.classList.add('hidden');
|
||||
successPanel.classList.remove('hidden');
|
||||
|
||||
successTitle.textContent = currentMode === 'phone' ? '인증링크 발송 완료' : '로그인 성공';
|
||||
successDescription.textContent = currentMode === 'phone'
|
||||
? `${identifier} 번호로 인증 링크를 보냈습니다.`
|
||||
: `${identifier} 계정으로 접속되었습니다.`;
|
||||
} else {
|
||||
alert(result.message || '오류가 발생했습니다.');
|
||||
submitButton.disabled = false;
|
||||
submitButton.textContent = originalBtnText;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Request failed', error);
|
||||
alert('서버 통신에 실패했습니다.');
|
||||
submitButton.disabled = false;
|
||||
submitButton.textContent = originalBtnText;
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user