[feat]: 회원가입 페이지 개선 및 폼 자동 포맷팅 기능 추가
주요 변경사항: - 회원가입 폼에 사업자등록번호 자동 포맷팅 (000-00-00000) - 핸드폰 번호 자동 포맷팅 (010-1111-1111 / 010-111-1111) - 약관 전체 동의 체크박스 추가 및 개별 약관 연동 - 모든 입력 필드에 autocomplete 속성 추가 (브라우저 자동완성 지원) - 회원가입 API 연동 및 백엔드 통신 구현 - LoginPage 폼 태그 추가 및 DOM 경고 수정 - LanguageSelect 언어 변경 시 전체 페이지 새로고침으로 변경 - 다국어 번역 키 추가 (ko, en, ja) 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -46,13 +46,14 @@ export class ApiClient {
|
||||
// API Key만 사용 (이미 위에서 추가됨)
|
||||
break;
|
||||
|
||||
case 'bearer':
|
||||
case 'bearer': {
|
||||
const token = this.getToken?.();
|
||||
if (token) {
|
||||
headers['Authorization'] = `Bearer ${token}`;
|
||||
}
|
||||
// API Key도 함께 전송 (이미 위에서 추가됨)
|
||||
break;
|
||||
}
|
||||
|
||||
case 'sanctum':
|
||||
// 쿠키 기반 - 별도 헤더 불필요
|
||||
@@ -134,11 +135,25 @@ export class ApiClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* 에러 처리
|
||||
* 에러 처리 (자동 토큰 갱신 포함)
|
||||
*/
|
||||
private async handleError(response: Response): Promise<never> {
|
||||
const data = await response.json().catch(() => ({}));
|
||||
|
||||
// 401 Unauthorized - Try token refresh
|
||||
if (response.status === 401) {
|
||||
console.warn('⚠️ 401 Unauthorized - Token may be expired');
|
||||
|
||||
// Client-side: Suggest token refresh to caller
|
||||
throw {
|
||||
status: 401,
|
||||
message: 'Unauthorized - Token expired',
|
||||
needsTokenRefresh: true,
|
||||
errors: data.errors,
|
||||
code: data.code,
|
||||
};
|
||||
}
|
||||
|
||||
const error: ApiErrorResponse = {
|
||||
message: data.message || 'An error occurred',
|
||||
errors: data.errors,
|
||||
@@ -150,4 +165,49 @@ export class ApiClient {
|
||||
...error,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to handle API calls with automatic token refresh
|
||||
*
|
||||
* Usage:
|
||||
* ```typescript
|
||||
* const data = await withTokenRefresh(() => apiClient.get('/protected'));
|
||||
* ```
|
||||
*/
|
||||
export async function withTokenRefresh<T>(
|
||||
apiCall: () => Promise<T>,
|
||||
maxRetries: number = 1
|
||||
): Promise<T> {
|
||||
try {
|
||||
return await apiCall();
|
||||
} catch (error: unknown) {
|
||||
const apiError = error as { status?: number; needsTokenRefresh?: boolean };
|
||||
|
||||
// If 401 and token refresh needed, try refreshing
|
||||
if (apiError.status === 401 && apiError.needsTokenRefresh && maxRetries > 0) {
|
||||
console.log('🔄 Attempting token refresh...');
|
||||
|
||||
// Call refresh endpoint
|
||||
const refreshResponse = await fetch('/api/auth/refresh', {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
});
|
||||
|
||||
if (refreshResponse.ok) {
|
||||
console.log('✅ Token refreshed, retrying API call');
|
||||
// Retry the original API call
|
||||
return withTokenRefresh(apiCall, maxRetries - 1);
|
||||
} else {
|
||||
console.error('❌ Token refresh failed - redirecting to login');
|
||||
// Refresh failed - redirect to login
|
||||
if (typeof window !== 'undefined') {
|
||||
window.location.href = '/login';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Re-throw error if not handled
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user