163 lines
5.6 KiB
TypeScript
163 lines
5.6 KiB
TypeScript
import axios, { AxiosInstance, AxiosResponse } from 'axios';
|
|
import supabase from './supabase';
|
|
|
|
// Type definitions
|
|
interface LoginCredentials {
|
|
email: string;
|
|
password: string;
|
|
}
|
|
|
|
interface LoginResponse {
|
|
success: boolean;
|
|
token: string;
|
|
user: {
|
|
id: string;
|
|
email: string;
|
|
name?: string;
|
|
};
|
|
}
|
|
|
|
// Create a reusable Axios instance with default configuration
|
|
const apiClient: AxiosInstance = axios.create({
|
|
baseURL: 'http://localhost:4000',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
timeout: 10000, // 10 seconds timeout
|
|
});
|
|
|
|
// Request interceptor for adding auth token
|
|
apiClient.interceptors.request.use(
|
|
async (config) => {
|
|
// 从 Supabase 获取当前会话
|
|
const { data } = await supabase.auth.getSession();
|
|
const session = data.session;
|
|
|
|
if (session) {
|
|
config.headers.Authorization = `Bearer ${session.access_token}`;
|
|
}
|
|
return config;
|
|
},
|
|
(error) => {
|
|
return Promise.reject(error);
|
|
}
|
|
);
|
|
|
|
// Response interceptor for handling common errors
|
|
apiClient.interceptors.response.use(
|
|
(response) => {
|
|
return response;
|
|
},
|
|
async (error) => {
|
|
// Handle errors globally
|
|
if (error.response) {
|
|
// Server responded with error status (4xx, 5xx)
|
|
if (error.response.status === 401) {
|
|
// Unauthorized - 可能是 token 过期,尝试刷新
|
|
try {
|
|
const { data, error: refreshError } = await supabase.auth.refreshSession();
|
|
|
|
if (refreshError || !data.session) {
|
|
// 刷新失败,重定向到登录页面
|
|
if (window.location.pathname !== '/login') {
|
|
window.location.href = '/login';
|
|
}
|
|
} else {
|
|
// 刷新成功,重试请求
|
|
const originalRequest = error.config;
|
|
originalRequest.headers.Authorization = `Bearer ${data.session.access_token}`;
|
|
return axios(originalRequest);
|
|
}
|
|
} catch (refreshError) {
|
|
console.error('Failed to refresh token:', refreshError);
|
|
// 重定向到登录页面
|
|
if (window.location.pathname !== '/login') {
|
|
window.location.href = '/login';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return Promise.reject(error);
|
|
}
|
|
);
|
|
|
|
// Auth API - 不再需要大部分方法,因为现在直接使用 Supabase
|
|
export const authApi = {
|
|
// 保留 verify 方法用于与后端验证
|
|
verify: async (): Promise<AxiosResponse> => {
|
|
const { data } = await supabase.auth.getSession();
|
|
const session = data.session;
|
|
|
|
if (!session) {
|
|
throw new Error('No active session');
|
|
}
|
|
|
|
return apiClient.get('/api/auth/verify', {
|
|
headers: {
|
|
Authorization: `Bearer ${session.access_token}`
|
|
}
|
|
});
|
|
}
|
|
};
|
|
|
|
// Comments API
|
|
export const commentsApi = {
|
|
getComments: (params?: Record<string, string | number | boolean>): Promise<AxiosResponse> =>
|
|
apiClient.get('/api/comments', { params }),
|
|
getComment: (id: string): Promise<AxiosResponse> =>
|
|
apiClient.get(`/api/comments/${id}`),
|
|
createComment: (data: Record<string, unknown>): Promise<AxiosResponse> =>
|
|
apiClient.post('/api/comments', data),
|
|
updateComment: (id: string, data: Record<string, unknown>): Promise<AxiosResponse> =>
|
|
apiClient.put(`/api/comments/${id}`, data),
|
|
deleteComment: (id: string): Promise<AxiosResponse> =>
|
|
apiClient.delete(`/api/comments/${id}`),
|
|
};
|
|
|
|
// Posts API
|
|
export const postsApi = {
|
|
getPosts: (params?: Record<string, string | number | boolean>): Promise<AxiosResponse> =>
|
|
apiClient.get('/api/posts', { params }),
|
|
getPost: (id: string): Promise<AxiosResponse> =>
|
|
apiClient.get(`/api/posts/${id}`),
|
|
createPost: (data: Record<string, unknown>): Promise<AxiosResponse> =>
|
|
apiClient.post('/api/posts', data),
|
|
updatePost: (id: string, data: Record<string, unknown>): Promise<AxiosResponse> =>
|
|
apiClient.put(`/api/posts/${id}`, data),
|
|
deletePost: (id: string): Promise<AxiosResponse> =>
|
|
apiClient.delete(`/api/posts/${id}`),
|
|
};
|
|
|
|
// Analytics API
|
|
export const analyticsApi = {
|
|
getPlatforms: (timeRange: string): Promise<AxiosResponse> =>
|
|
apiClient.get(`/api/analytics/platforms?timeRange=${timeRange}`),
|
|
getTimeline: (timeRange: string): Promise<AxiosResponse> =>
|
|
apiClient.get(`/api/analytics/timeline?timeRange=${timeRange}`),
|
|
getSentiment: (timeRange: string): Promise<AxiosResponse> =>
|
|
apiClient.get(`/api/analytics/sentiment?timeRange=${timeRange}`),
|
|
getStatus: (timeRange: string): Promise<AxiosResponse> =>
|
|
apiClient.get(`/api/analytics/status?timeRange=${timeRange}`),
|
|
getPopularContent: (timeRange: string): Promise<AxiosResponse> =>
|
|
apiClient.get(`/api/analytics/popular-content?timeRange=${timeRange}`),
|
|
getInfluencers: (timeRange: string): Promise<AxiosResponse> =>
|
|
apiClient.get(`/api/analytics/influencers?timeRange=${timeRange}`),
|
|
getConversion: (timeRange: string): Promise<AxiosResponse> =>
|
|
apiClient.get(`/api/analytics/conversion?timeRange=${timeRange}`),
|
|
};
|
|
|
|
// Templates API
|
|
export const templatesApi = {
|
|
getTemplates: (): Promise<AxiosResponse> =>
|
|
apiClient.get('/api/reply-templates'),
|
|
getTemplate: (id: string): Promise<AxiosResponse> =>
|
|
apiClient.get(`/api/reply-templates/${id}`),
|
|
createTemplate: (data: Record<string, unknown>): Promise<AxiosResponse> =>
|
|
apiClient.post('/api/reply-templates', data),
|
|
updateTemplate: (id: string, data: Record<string, unknown>): Promise<AxiosResponse> =>
|
|
apiClient.put(`/api/reply-templates/${id}`, data),
|
|
deleteTemplate: (id: string): Promise<AxiosResponse> =>
|
|
apiClient.delete(`/api/reply-templates/${id}`),
|
|
};
|
|
|
|
export default apiClient;
|