All files / src/services api.ts

0% Statements 0/20
0% Branches 0/3
0% Functions 0/4
0% Lines 0/20

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126                                                                                                                                                                                                                                                           
import axios, { type AxiosInstance, type AxiosResponse } from "axios";
 
export interface ApiResponse<T = any> {
  data: T;
  status: number;
  statusText: string;
}
 
export interface LoginRequest {
  username: string;
  password: string;
}
 
export interface LoginResponse {
  success: boolean;
  message: string;
  token: string;
}
 
export interface ProductRequest {
  name: string;
  price: number;
  quantity: number;
  description: string;
  category: string;
}
 
export interface ProductResponse {
  id: number;
  name: string;
  price: number;
  quantity: number;
  description: string;
  category: string;
}
 
class ApiClient {
  private client: AxiosInstance;
 
  private readonly API_BASE_URL =
    import.meta.env.VITE_API_BASE_URL || "http://localhost:8080/api";
 
  constructor(baseURL: string = import.meta.env.VITE_API_BASE_URL) {
    this.client = axios.create({
      baseURL,
      timeout: 10000,
      headers: {
        "Content-Type": "application/json",
      },
    });
 
    this.setupInterceptors();
  }
 
  private setupInterceptors(): void {
    // Request interceptor
    this.client.interceptors.request.use(
      (config: any) => {
        const token = localStorage.getItem("authToken");
        if (token) {
          config.headers.Authorization = `Bearer ${token}`;
        }
        return config;
      },
      (error: any) => Promise.reject(error)
    );
 
    // Response interceptor
    this.client.interceptors.response.use(
      (response: any) => response,
      (error: any) => {
        if (error.response?.status === 401) {
          localStorage.removeItem("authToken");
          window.location.href = "/login";
        }
        return Promise.reject(error);
      }
    );
  }
 
  // Auth method
  async login(
    credentials: LoginRequest
  ): Promise<AxiosResponse<LoginResponse>> {
    return this.client.post<LoginResponse>(
      this.API_BASE_URL + "/auth/login",
      credentials
    );
  }
 
  // Product methods
  async getProducts(params?: {
    name?: string;
    category?: string;
    page?: number;
    size?: number;
  }): Promise<AxiosResponse<{ content: ProductResponse[] }>> {
    return this.client.get(this.API_BASE_URL + "/products", {
      params,
    });
  }
 
  async getProductById(id: number): Promise<AxiosResponse<ProductResponse>> {
    return this.client.get(this.API_BASE_URL + `/products/${id}`);
  }
 
  async createProduct(
    product: ProductRequest
  ): Promise<AxiosResponse<ProductResponse>> {
    return this.client.post(this.API_BASE_URL + "/products", product);
  }
 
  async updateProduct(
    id: number,
    product: ProductRequest
  ): Promise<AxiosResponse<ProductResponse>> {
    return this.client.put(this.API_BASE_URL + `/products/${id}`, product);
  }
 
  async deleteProduct(id: number): Promise<AxiosResponse<void>> {
    return this.client.delete(this.API_BASE_URL + `/products/${id}`);
  }
}
 
export const apiClient = new ApiClient();