164 lines
4.3 KiB
TypeScript
164 lines
4.3 KiB
TypeScript
// Auth service for handling authentication API calls
|
|
|
|
import { authApiClient } from '@/lib/api/client'
|
|
import { getUserFriendlyErrorMessage } from '@/lib/api/errorHandler'
|
|
|
|
export interface LoginRequest {
|
|
email: string;
|
|
password: string;
|
|
}
|
|
|
|
export interface RegisterRequest {
|
|
username: string;
|
|
email: string;
|
|
password: string;
|
|
}
|
|
|
|
export interface User {
|
|
id: string;
|
|
username: string;
|
|
email: string;
|
|
displayName: string | null;
|
|
avatarUrl: string | null;
|
|
subscriptionType: string;
|
|
}
|
|
|
|
export interface AuthResponse {
|
|
success: boolean;
|
|
data?: {
|
|
token: string;
|
|
user: User;
|
|
};
|
|
error?: string;
|
|
}
|
|
|
|
import { BASE_URL } from '@/lib/config/api'
|
|
|
|
const API_BASE_URL = BASE_URL;
|
|
|
|
class AuthService {
|
|
private async makeRequest<T>(
|
|
endpoint: string,
|
|
options: RequestInit = {}
|
|
): Promise<T> {
|
|
const url = `${API_BASE_URL}/api/auth${endpoint}`;
|
|
|
|
console.log('Making request to:', url)
|
|
console.log('Request body:', options.body)
|
|
|
|
const response = await fetch(url, {
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
...options.headers,
|
|
},
|
|
...options,
|
|
});
|
|
|
|
if (!response.ok) {
|
|
const errorData = await response.json().catch(() => ({ error: 'Network error' }));
|
|
console.log('API Error Response:', errorData)
|
|
|
|
// 處理驗證錯誤 (400 Bad Request)
|
|
if (response.status === 400 && errorData.errors) {
|
|
const validationErrors = Object.entries(errorData.errors)
|
|
.map(([field, messages]: [string, any]) => `${field}: ${Array.isArray(messages) ? messages.join(', ') : messages}`)
|
|
.join('\n');
|
|
throw new Error(validationErrors);
|
|
}
|
|
|
|
throw new Error(errorData.error || errorData.title || `HTTP ${response.status}`);
|
|
}
|
|
|
|
return response.json();
|
|
}
|
|
|
|
async login(data: LoginRequest): Promise<AuthResponse> {
|
|
try {
|
|
const response = await this.makeRequest<AuthResponse>('/login', {
|
|
method: 'POST',
|
|
body: JSON.stringify(data),
|
|
});
|
|
|
|
if (response.success && response.data?.token) {
|
|
// Store token in localStorage
|
|
localStorage.setItem('auth_token', response.data.token);
|
|
localStorage.setItem('user_data', JSON.stringify(response.data.user));
|
|
}
|
|
|
|
return response;
|
|
} catch (error) {
|
|
return {
|
|
success: false,
|
|
error: error instanceof Error ? error.message : 'Login failed',
|
|
};
|
|
}
|
|
}
|
|
|
|
async register(data: RegisterRequest): Promise<AuthResponse> {
|
|
try {
|
|
console.log('AuthService.register called with:', {
|
|
username: data.username,
|
|
email: data.email,
|
|
password: data.password ? '[hidden]' : 'empty'
|
|
})
|
|
|
|
const response = await this.makeRequest<AuthResponse>('/register', {
|
|
method: 'POST',
|
|
body: JSON.stringify(data),
|
|
});
|
|
|
|
if (response.success && response.data?.token) {
|
|
// Store token in localStorage
|
|
localStorage.setItem('auth_token', response.data.token);
|
|
localStorage.setItem('user_data', JSON.stringify(response.data.user));
|
|
}
|
|
|
|
return response;
|
|
} catch (error) {
|
|
return {
|
|
success: false,
|
|
error: error instanceof Error ? error.message : 'Registration failed',
|
|
};
|
|
}
|
|
}
|
|
|
|
async logout(): Promise<void> {
|
|
localStorage.removeItem('auth_token');
|
|
localStorage.removeItem('user_data');
|
|
}
|
|
|
|
getToken(): string | null {
|
|
if (typeof window === 'undefined') return null;
|
|
return localStorage.getItem('auth_token');
|
|
}
|
|
|
|
getUser(): User | null {
|
|
if (typeof window === 'undefined') return null;
|
|
const userData = localStorage.getItem('user_data');
|
|
return userData ? JSON.parse(userData) : null;
|
|
}
|
|
|
|
isAuthenticated(): boolean {
|
|
return this.getToken() !== null;
|
|
}
|
|
|
|
async checkAuthStatus(): Promise<boolean> {
|
|
const token = this.getToken();
|
|
if (!token) return false;
|
|
|
|
try {
|
|
await this.makeRequest('/status', {
|
|
headers: {
|
|
'Authorization': `Bearer ${token}`,
|
|
},
|
|
});
|
|
return true;
|
|
} catch {
|
|
// Token is invalid, clear it
|
|
this.logout();
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
export const authService = new AuthService(); |