288 lines
No EOL
7 KiB
TypeScript
288 lines
No EOL
7 KiB
TypeScript
import axios from 'axios';
|
|
|
|
// Types for API responses
|
|
export interface ApiResponse<T = any> {
|
|
success: boolean;
|
|
data: T;
|
|
message: string;
|
|
}
|
|
|
|
export interface ApiError {
|
|
success: false;
|
|
message: string;
|
|
errors?: Record<string, string[]>;
|
|
}
|
|
|
|
export interface PaginatedResponse<T> {
|
|
data: T[];
|
|
pagination: {
|
|
current_page: number;
|
|
last_page: number;
|
|
per_page: number;
|
|
total: number;
|
|
from: number | null;
|
|
to: number | null;
|
|
};
|
|
}
|
|
|
|
// User types
|
|
export interface User {
|
|
id: number;
|
|
name: string;
|
|
email: string;
|
|
}
|
|
|
|
export interface LoginCredentials {
|
|
email: string;
|
|
password: string;
|
|
}
|
|
|
|
export interface RegisterData {
|
|
name: string;
|
|
email: string;
|
|
password: string;
|
|
password_confirmation: string;
|
|
}
|
|
|
|
export interface AuthResponse {
|
|
user: User;
|
|
token: string;
|
|
token_type: string;
|
|
}
|
|
|
|
// Article types
|
|
export interface Article {
|
|
id: number;
|
|
feed_id: number;
|
|
url: string;
|
|
title: string;
|
|
description: string;
|
|
is_valid: boolean;
|
|
is_duplicate: boolean;
|
|
approval_status: 'pending' | 'approved' | 'rejected';
|
|
approved_at: string | null;
|
|
approved_by: string | null;
|
|
fetched_at: string | null;
|
|
validated_at: string | null;
|
|
created_at: string;
|
|
updated_at: string;
|
|
feed?: Feed;
|
|
article_publication?: ArticlePublication;
|
|
}
|
|
|
|
// Feed types
|
|
export interface Feed {
|
|
id: number;
|
|
name: string;
|
|
url: string;
|
|
type: 'website' | 'rss';
|
|
is_active: boolean;
|
|
description: string | null;
|
|
created_at: string;
|
|
updated_at: string;
|
|
articles_count?: number;
|
|
}
|
|
|
|
// Other types
|
|
export interface ArticlePublication {
|
|
id: number;
|
|
article_id: number;
|
|
status: string;
|
|
published_at: string | null;
|
|
created_at: string;
|
|
updated_at: string;
|
|
}
|
|
|
|
export interface PlatformAccount {
|
|
id: number;
|
|
platform_instance_id: number;
|
|
account_id: string;
|
|
username: string;
|
|
display_name: string | null;
|
|
description: string | null;
|
|
is_active: boolean;
|
|
created_at: string;
|
|
updated_at: string;
|
|
}
|
|
|
|
export interface PlatformChannel {
|
|
id: number;
|
|
platform_instance_id: number;
|
|
channel_id: string;
|
|
name: string;
|
|
display_name: string | null;
|
|
description: string | null;
|
|
is_active: boolean;
|
|
created_at: string;
|
|
updated_at: string;
|
|
}
|
|
|
|
export interface Settings {
|
|
article_processing_enabled: boolean;
|
|
publishing_approvals_enabled: boolean;
|
|
}
|
|
|
|
export interface DashboardStats {
|
|
article_stats: {
|
|
total_today: number;
|
|
total_week: number;
|
|
total_month: number;
|
|
approved_today: number;
|
|
approved_week: number;
|
|
approved_month: number;
|
|
approval_percentage_today: number;
|
|
approval_percentage_week: number;
|
|
approval_percentage_month: number;
|
|
};
|
|
system_stats: {
|
|
total_feeds: number;
|
|
active_feeds: number;
|
|
total_platform_accounts: number;
|
|
active_platform_accounts: number;
|
|
total_platform_channels: number;
|
|
active_platform_channels: number;
|
|
total_routes: number;
|
|
active_routes: number;
|
|
};
|
|
available_periods: Array<{ value: string; label: string }>;
|
|
current_period: string;
|
|
}
|
|
|
|
// API Client class
|
|
class ApiClient {
|
|
private token: string | null = null;
|
|
|
|
constructor() {
|
|
// Get token from localStorage if available
|
|
this.token = localStorage.getItem('auth_token');
|
|
this.setupInterceptors();
|
|
}
|
|
|
|
private setupInterceptors() {
|
|
// Request interceptor to add auth token
|
|
axios.interceptors.request.use((config) => {
|
|
if (this.token) {
|
|
config.headers.Authorization = `Bearer ${this.token}`;
|
|
}
|
|
return config;
|
|
});
|
|
|
|
// Response interceptor to handle errors
|
|
axios.interceptors.response.use(
|
|
(response) => response,
|
|
(error) => {
|
|
if (error.response?.status === 401) {
|
|
this.clearAuth();
|
|
window.location.href = '/login';
|
|
}
|
|
return Promise.reject(error);
|
|
}
|
|
);
|
|
}
|
|
|
|
setAuth(token: string, user: User) {
|
|
this.token = token;
|
|
localStorage.setItem('auth_token', token);
|
|
localStorage.setItem('user', JSON.stringify(user));
|
|
}
|
|
|
|
clearAuth() {
|
|
this.token = null;
|
|
localStorage.removeItem('auth_token');
|
|
localStorage.removeItem('user');
|
|
}
|
|
|
|
getUser(): User | null {
|
|
const userStr = localStorage.getItem('user');
|
|
return userStr ? JSON.parse(userStr) : null;
|
|
}
|
|
|
|
isAuthenticated(): boolean {
|
|
return !!this.token;
|
|
}
|
|
|
|
// Auth endpoints
|
|
async login(credentials: LoginCredentials): Promise<AuthResponse> {
|
|
const response = await axios.post<ApiResponse<AuthResponse>>('/auth/login', credentials);
|
|
return response.data.data;
|
|
}
|
|
|
|
async register(data: RegisterData): Promise<AuthResponse> {
|
|
const response = await axios.post<ApiResponse<AuthResponse>>('/auth/register', data);
|
|
return response.data.data;
|
|
}
|
|
|
|
async logout(): Promise<void> {
|
|
await axios.post('/auth/logout');
|
|
this.clearAuth();
|
|
}
|
|
|
|
async me(): Promise<User> {
|
|
const response = await axios.get<ApiResponse<{ user: User }>>('/auth/me');
|
|
return response.data.data.user;
|
|
}
|
|
|
|
// Dashboard endpoints
|
|
async getDashboardStats(period = 'today'): Promise<DashboardStats> {
|
|
const response = await axios.get<ApiResponse<DashboardStats>>('/dashboard/stats', {
|
|
params: { period }
|
|
});
|
|
return response.data.data;
|
|
}
|
|
|
|
// Articles endpoints
|
|
async getArticles(page = 1, perPage = 15): Promise<{ articles: Article[]; pagination: any; settings: any }> {
|
|
const response = await axios.get<ApiResponse<{ articles: Article[]; pagination: any; settings: any }>>('/articles', {
|
|
params: { page, per_page: perPage }
|
|
});
|
|
return response.data.data;
|
|
}
|
|
|
|
async approveArticle(articleId: number): Promise<Article> {
|
|
const response = await axios.post<ApiResponse<Article>>(`/articles/${articleId}/approve`);
|
|
return response.data.data;
|
|
}
|
|
|
|
async rejectArticle(articleId: number): Promise<Article> {
|
|
const response = await axios.post<ApiResponse<Article>>(`/articles/${articleId}/reject`);
|
|
return response.data.data;
|
|
}
|
|
|
|
// Feeds endpoints
|
|
async getFeeds(): Promise<Feed[]> {
|
|
const response = await axios.get<ApiResponse<Feed[]>>('/feeds');
|
|
return response.data.data;
|
|
}
|
|
|
|
async createFeed(data: Partial<Feed>): Promise<Feed> {
|
|
const response = await axios.post<ApiResponse<Feed>>('/feeds', data);
|
|
return response.data.data;
|
|
}
|
|
|
|
async updateFeed(id: number, data: Partial<Feed>): Promise<Feed> {
|
|
const response = await axios.put<ApiResponse<Feed>>(`/feeds/${id}`, data);
|
|
return response.data.data;
|
|
}
|
|
|
|
async deleteFeed(id: number): Promise<void> {
|
|
await axios.delete(`/feeds/${id}`);
|
|
}
|
|
|
|
async toggleFeed(id: number): Promise<Feed> {
|
|
const response = await axios.post<ApiResponse<Feed>>(`/feeds/${id}/toggle`);
|
|
return response.data.data;
|
|
}
|
|
|
|
// Settings endpoints
|
|
async getSettings(): Promise<Settings> {
|
|
const response = await axios.get<ApiResponse<Settings>>('/settings');
|
|
return response.data.data;
|
|
}
|
|
|
|
async updateSettings(data: Partial<Settings>): Promise<Settings> {
|
|
const response = await axios.put<ApiResponse<Settings>>('/settings', data);
|
|
return response.data.data;
|
|
}
|
|
}
|
|
|
|
export const apiClient = new ApiClient(); |