265 lines
6.3 KiB
TypeScript
265 lines
6.3 KiB
TypeScript
import toast from "react-hot-toast";
|
|
|
|
interface ApiResponse<T = any> {
|
|
message: string;
|
|
data: T;
|
|
state: number;
|
|
time: number;
|
|
errorCode: number;
|
|
resultType: number;
|
|
}
|
|
|
|
class ApiService {
|
|
private baseURL = "https://inogen-back.pelekan.org/api";
|
|
private token: string | null = null;
|
|
|
|
constructor() {
|
|
// Initialize token from localStorage
|
|
this.initializeToken();
|
|
}
|
|
|
|
private initializeToken() {
|
|
try {
|
|
const savedToken = localStorage.getItem("auth_token");
|
|
if (savedToken) {
|
|
const tokenData = JSON.parse(savedToken);
|
|
this.token = tokenData.accessToken;
|
|
}
|
|
} catch (error) {
|
|
console.error("Error initializing token:", error);
|
|
}
|
|
}
|
|
|
|
public setToken(token: string) {
|
|
this.token = token;
|
|
}
|
|
|
|
public clearToken() {
|
|
this.token = null;
|
|
}
|
|
|
|
private async request<T = any>(
|
|
endpoint: string,
|
|
options: RequestInit = {}
|
|
): Promise<ApiResponse<T>> {
|
|
const url = `${this.baseURL}${endpoint}`;
|
|
|
|
const defaultHeaders: HeadersInit = {
|
|
"Content-Type": "application/json",
|
|
};
|
|
|
|
// Add authorization header if token exists
|
|
if (this.token) {
|
|
defaultHeaders.Authorization = `Bearer ${this.token}`;
|
|
}
|
|
|
|
const config: RequestInit = {
|
|
...options,
|
|
headers: {
|
|
...defaultHeaders,
|
|
...options.headers,
|
|
},
|
|
};
|
|
|
|
try {
|
|
const response = await fetch(url, config);
|
|
const data: ApiResponse<T> = await response.json();
|
|
|
|
// Handle different response states
|
|
if (!response.ok) {
|
|
throw new Error(data.message || `HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
if (data.state !== 0) {
|
|
throw new Error(data.message || "API error occurred");
|
|
}
|
|
|
|
return data;
|
|
} catch (error) {
|
|
console.error("API request failed:", error);
|
|
|
|
// Handle network errors
|
|
if (error instanceof TypeError && error.message.includes("fetch")) {
|
|
toast.error("خطا در اتصال به سرور. لطفاً اتصال اینترنت خود را بررسی کنید");
|
|
throw new Error("شبکه در دسترس نیست");
|
|
}
|
|
|
|
// Handle authentication errors
|
|
if (error instanceof Error && error.message.includes("401")) {
|
|
toast.error("جلسه کاری شما منقضی شده است. لطفاً دوباره وارد شوید");
|
|
this.clearToken();
|
|
localStorage.removeItem("auth_token");
|
|
localStorage.removeItem("auth_user");
|
|
window.location.href = "/login";
|
|
throw error;
|
|
}
|
|
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// GET request
|
|
public async get<T = any>(endpoint: string): Promise<ApiResponse<T>> {
|
|
return this.request<T>(endpoint, {
|
|
method: "GET",
|
|
});
|
|
}
|
|
|
|
// POST request
|
|
public async post<T = any>(
|
|
endpoint: string,
|
|
data?: any
|
|
): Promise<ApiResponse<T>> {
|
|
return this.request<T>(endpoint, {
|
|
method: "POST",
|
|
body: data ? JSON.stringify(data) : undefined,
|
|
});
|
|
}
|
|
|
|
// PUT request
|
|
public async put<T = any>(
|
|
endpoint: string,
|
|
data?: any
|
|
): Promise<ApiResponse<T>> {
|
|
return this.request<T>(endpoint, {
|
|
method: "PUT",
|
|
body: data ? JSON.stringify(data) : undefined,
|
|
});
|
|
}
|
|
|
|
// DELETE request
|
|
public async delete<T = any>(endpoint: string): Promise<ApiResponse<T>> {
|
|
return this.request<T>(endpoint, {
|
|
method: "DELETE",
|
|
});
|
|
}
|
|
|
|
// PATCH request
|
|
public async patch<T = any>(
|
|
endpoint: string,
|
|
data?: any
|
|
): Promise<ApiResponse<T>> {
|
|
return this.request<T>(endpoint, {
|
|
method: "PATCH",
|
|
body: data ? JSON.stringify(data) : undefined,
|
|
});
|
|
}
|
|
|
|
// Authentication methods
|
|
public async login(username: string, password: string) {
|
|
try {
|
|
const response = await this.post("/login", {
|
|
username,
|
|
password,
|
|
});
|
|
|
|
if (response.state === 0) {
|
|
const parsedData = JSON.parse(response.data);
|
|
this.setToken(parsedData.Token.AccessToken);
|
|
return {
|
|
success: true,
|
|
data: parsedData,
|
|
message: response.message,
|
|
};
|
|
}
|
|
|
|
return {
|
|
success: false,
|
|
message: response.message || "ورود ناموفق",
|
|
};
|
|
} catch (error) {
|
|
return {
|
|
success: false,
|
|
message: error instanceof Error ? error.message : "خطای غیرمنتظره",
|
|
};
|
|
}
|
|
}
|
|
|
|
public async logout() {
|
|
try {
|
|
// Call logout endpoint if it exists
|
|
await this.post("/logout");
|
|
} catch (error) {
|
|
console.error("Logout API call failed:", error);
|
|
} finally {
|
|
// Clear token regardless of API call success
|
|
this.clearToken();
|
|
localStorage.removeItem("auth_token");
|
|
localStorage.removeItem("auth_user");
|
|
}
|
|
}
|
|
|
|
// Profile methods
|
|
public async getProfile() {
|
|
return this.get("/profile");
|
|
}
|
|
|
|
public async updateProfile(data: any) {
|
|
return this.put("/profile", data);
|
|
}
|
|
|
|
// Projects methods
|
|
public async getProjects() {
|
|
return this.get("/projects");
|
|
}
|
|
|
|
public async getProject(id: number) {
|
|
return this.get(`/projects/${id}`);
|
|
}
|
|
|
|
public async createProject(data: any) {
|
|
return this.post("/projects", data);
|
|
}
|
|
|
|
public async updateProject(id: number, data: any) {
|
|
return this.put(`/projects/${id}`, data);
|
|
}
|
|
|
|
public async deleteProject(id: number) {
|
|
return this.delete(`/projects/${id}`);
|
|
}
|
|
|
|
// Dashboard methods
|
|
public async getDashboardStats() {
|
|
return this.get("/dashboard/stats");
|
|
}
|
|
|
|
public async getDashboardRecentActivity() {
|
|
return this.get("/dashboard/recent-activity");
|
|
}
|
|
|
|
// File upload method
|
|
public async uploadFile(file: File, endpoint: string = "/upload") {
|
|
const formData = new FormData();
|
|
formData.append("file", file);
|
|
|
|
const config: RequestInit = {
|
|
method: "POST",
|
|
headers: this.token ? { Authorization: `Bearer ${this.token}` } : {},
|
|
body: formData,
|
|
};
|
|
|
|
try {
|
|
const response = await fetch(`${this.baseURL}${endpoint}`, config);
|
|
const data = await response.json();
|
|
|
|
if (!response.ok) {
|
|
throw new Error(data.message || `HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
return data;
|
|
} catch (error) {
|
|
console.error("File upload failed:", error);
|
|
throw error;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Create and export a singleton instance
|
|
const apiService = new ApiService();
|
|
|
|
export default apiService;
|
|
|
|
// Export types for use in components
|
|
export type { ApiResponse };
|