<reponame>MartyFibghtov/kernel-housing<filename>frontend/src/API/HousingApi.js<gh_stars>0import axios from "axios";
import Cookies from "js-cookie";

const apiBaseUrl = "http://127.0.0.1:8000/";

class HousingApi {
  STATUS_CLOSED = "Закрыта";

  constructor() {
    this.token = Cookies.get("token");
    this.is_authorised = false;
    if (this.token) {
      this.is_authorised = true;
    }
    this.apiBaseUrl = "http://127.0.0.1:8000/";

    this.entranceRequests = [];
    this.cars = null;
    this.addresses = null;
    this.streets = null;
    this.carTypes = null;
    this.carMarks = null;
    this.requestPrices = null;
    this.isDataLoaded = false;
    this.user = null;
  }

  getAuthorizationHeader() {
    const headers = { Authorization: `Token ${this.token}` };
    return headers;
  }

  static async handleResponse(response) {
    if (response.status == 200) {
      return response.data;
    } else {
      let error;
      let data = response.data;
      switch (response.status) {
        case 400:
          error = new Error(data.message || "Bad Request");
          break;
        case 401:
          error = new Error(data.message || "Unauthorized");
          break;
        case 403:
          error = new Error(data.message || "Forbidden");
          break;
        case 404:
          error = new Error(data.message || "Not Found");
          break;
        case 500:
          error = new Error(data.message || "Internal Server Error");
          break;
        default:
          error = new Error("Unknown Error");
          break;
      }
      error.response = response;
      // throw error;
    }
  }

  async handleResponse(response) {
    return await HousingApi.handleResponse(response);
  }

  async _loadAllData() {
    if (!this.is_authorised) {
      return;
    }
    await this.getUserInfo();
    await this.getAllCars();
    await this.getAllCarTypes();
    await this.getAllStreets();
    await this.getAllAddresses();
    await this.getAllEntranceRequests();
    await this.getAllRequestPrices();

    this.isDataLoaded = true;
  }

  _eraseAllData() {
    this.is_authorised = false;
    this.entranceRequests = [];
    this.cars = null;
    this.addresses = null;
    this.streets = null;
    this.carTypes = null;
    this.carMarks = null;
    this.requestPrices = null;
    this.isDataLoaded = true;
    this.user = null;
  }

  async login(username, password) {
    const url = `${this.apiBaseUrl}/api/token-auth/`;
    const headers = { "Content-Type": "application/json" };
    const credentials = { username, password };
    const response = await axios.post(url, credentials, { headers });
    const data = await this.handleResponse(response);
    this.is_authorised = true;
    this.token = data.token;
    Cookies.set("token", data.token);

    // data is loaded only when authentication is done
    await this._loadAllData();
  }

  async logout() {
    Cookies.remove("token");
    this.token = null;
    this._eraseAllData();
  }

  async getUserInfo() {
    const url = `${apiBaseUrl}/api/users/get-info/`;
    const headers = this.getAuthorizationHeader();
    const response = await axios.get(url, { headers });
    const data = await HousingApi.handleResponse(response);

    this.user = data;
    return data;
  }

  static async getIsAdminUser() {
    const url = `${apiBaseUrl}/api/users/is_admin/`;
    const headers = { Authorization: `Token ${Cookies.get("token")}` };
    const response = await axios.get(url, { headers });
    const data = await HousingApi.handleResponse(response);

    return data;
  }

  async getAllCars() {
    if (this.cars != null) {
      return this.cars;
    }
    const url = `${this.apiBaseUrl}/api/cars/get-all/`;
    const headers = this.getAuthorizationHeader();
    const response = await axios.get(url, { headers });
    const data = await this.handleResponse(response);

    this.cars = data;

    return this.cars;
  }

  async getAllCarMarks() {
    if (this.carMarks != null) {
      return this.carMarks;
    }
    const url = `${this.apiBaseUrl}/api/cars/marks/get-all/`;
    const headers = this.getAuthorizationHeader();
    const response = await axios.get(url, { headers });
    const data = await this.handleResponse(response);

    this.carMarks = data;

    return this.carMarks;
  }

  async getAllCarTypes() {
    if (this.carTypes != null) {
      return this.carTypes;
    }
    const url = `${this.apiBaseUrl}/api/cars/types/get-all/`;
    const headers = this.getAuthorizationHeader();
    const response = await axios.get(url, { headers });
    const data = await this.handleResponse(response);

    this.carTypes = data;

    return this.carTypes;
  }

  // Entrance Requests

  async _updateEntranceRequest(newEntranceRequest, oldEntranceRequest) {
    // Method for updating entranceRequest data in the the list of this class to the most recent version available
    for (const key in newEntranceRequest) {
      if (oldEntranceRequest.hasOwnProperty(key)) {
        oldEntranceRequest[key] = newEntranceRequest[key];
      }
    }
  }

  async _updateRequestbyIdWithNewVal(requestId, newRequest) {
    // Method for updating entranceRequest data in the the list of this class to the most recent version available
    const oldRequest = this.getRequestByIdLocal(requestId);

    for (const key in newRequest) {
      if (newRequest.hasOwnProperty(key)) {
        oldRequest[key] = newRequest[key];
      }
    }
  }

  getRequestByIdLocal(request_id) {
    const request = this.entranceRequests.find(
      (request) => request.id === request_id
    );
    return request;
  }

  async _updateRequestById(request_id) {
    const newRequest = await this.getRequestById(request_id);
    const oldRequest = this.getRequestByIdLocal(request_id);
    await this._updateEntranceRequest(newRequest, oldRequest);
  }

  async _updateEntranceRequestByOldValue(oldRequest) {
    const newRequest = this.getRequestById(oldRequest.id);
    this._updateEntranceRequest(newRequest, oldRequest);
  }

  async _addNewRequest(newRequest) {
    this.entranceRequests.push(newRequest);
  }

  async _removeRequest(requestId) {
    this.entranceRequests = this.entranceRequests.filter(
      (item) => item.id != requestId
    );
  }

  async getAllEntranceRequests(periodStart = null, periodEnd = null) {
    const url = new URL(`${this.apiBaseUrl}/api/entrance-request/get-all/`);

    if (periodStart) {
      url.searchParams.set("period_start", periodStart);
    }
    if (periodEnd) {
      url.searchParams.set("period_end", periodEnd);
    }
    const headers = this.getAuthorizationHeader();
    const response = await axios.get(url, { headers });
    const data = await this.handleResponse(response);

    this.entranceRequests = data;

    return data;
  }

  async getRequestsUpdates(lastUpdated) {
    const url = new URL(`${this.apiBaseUrl}/api/entrance-requests/updates/`);

    url.searchParams.set("last_updated", lastUpdated);

    const headers = this.getAuthorizationHeader();
    const response = await axios.get(url, { headers });
    const data = await this.handleResponse(response);

    return data;
  }

  async getRequestById(request_id) {
    const url = new URL(`${this.apiBaseUrl}/api/entrance-request/get-by-id/`);
    url.searchParams.set("id", request_id);

    const headers = this.getAuthorizationHeader();
    const response = await axios.get(url, { headers });
    const data = await this.handleResponse(response);

    return data;
  }

  async createEntranceRequest(
    request_address_id,
    name_or_number,
    car_type,
    car_mark = null
  ) {
    const url = `${this.apiBaseUrl}/api/entrance-request/create/`;
    const headers = this.getAuthorizationHeader();
    const data = {
      request_address: request_address_id,
      name_or_number,
      car_type,
      car_mark,
    };

    const response = await axios.post(url, data, { headers });
    // newEntranceRequest = await this.handleResponse(response);

    const newEntranceRequest = await this.handleResponse(response);

    this._addNewRequest(newEntranceRequest);

    return newEntranceRequest;
  }

  async updateEntranceRequestCar(
    entrance_request_id,
    name_or_number,
    car_type,
    car_mark = null
  ) {
    const url = `${this.apiBaseUrl}/api/entrance-request/update/`;
    const headers = this.getAuthorizationHeader();
    const data = {
      id: entrance_request_id,
      name_or_number,
      car_type,
      car_mark,
    };
    const response = await axios.post(url, data, { headers });
    const newEntranceRequest = await this.handleResponse(response);

    const oldEntranceRequest = this.entranceRequests.find(
      (request) => request.id == entrance_request_id
    );

    this._updateEntranceRequest(newEntranceRequest, oldEntranceRequest);

    return newEntranceRequest;
  }

  async makeRequestNotActive(entrance_request) {
    const url = `${this.apiBaseUrl}/api/entrance-request/make-not-active/`;
    const headers = this.getAuthorizationHeader();
    const data = { id: entrance_request.id };
    const response = await axios.post(url, data, { headers });

    const responseData = await this.handleResponse(response);

    this._removeRequest(entrance_request.id);

    return responseData;
  }

  async getEntranceRequestSuggestions(address) {
    const url = `${this.apiBaseUrl}/api/entrance-request/get-address-suggestions/?address_id=${address.id}`;
    const headers = this.getAuthorizationHeader();
    const response = await axios.get(url, { headers });

    const responseData = await this.handleResponse(response);

    return responseData;
  }

  async getAllRequestPrices() {
    if (this.requestPrices != null) {
      return this.requestPrices;
    }

    const url = `${this.apiBaseUrl}/api/entrance-request/get-request-prices-all/`;
    const headers = this.getAuthorizationHeader();
    const response = await axios.get(url, { headers });

    const responseData = await this.handleResponse(response);
    this.requestPrices = responseData;

    return this.requestPrices;
  }

  async getRequestPrice(carType) {
    if (carType == "") {
      throw Error("Car type is empty");
    }

    const allRequestsPrices = await this.getAllRequestPrices();
    for (const requestPrice of allRequestsPrices) {
      if (requestPrice.car_type_name == carType) {
        return requestPrice;
      }
    }
    throw new Error("Car type not found");
  }

  // Personal accounts

  async getAllPersonalAccounts() {
    const url = `${this.apiBaseUrl}/api/address/personal-account/get-all/`;
    const headers = this.getAuthorizationHeader();
    const response = await axios.get(url, { headers });
    const data = await this.handleResponse(response);

    return data;
  }

  // Addresses

  async getAllAddresses() {
    if (this.addresses != null) {
      return this.addresses;
    }

    const url = `${this.apiBaseUrl}/api/address/address/get-all/`;
    const headers = this.getAuthorizationHeader();
    const response = await axios.get(url, { headers });
    const data = await this.handleResponse(response);

    this.addresses = data;

    return this.addresses;
  }

  async getAllStreets() {
    if (this.streets != null) {
      return this.streets;
    }
    const url = `${this.apiBaseUrl}/api/address/street/get-all/`;
    const headers = this.getAuthorizationHeader();
    const response = await axios.get(url, { headers });
    const data = await this.handleResponse(response);
    this.streets = data;

    return this.streets;
  }

  /**
   * Wrapper method for get all addresses that replaces street id with
   * object of street that have ID and Street name
   */
  // async getAllAddressesWithStreetsInfo() {
  //   if (this.addresses != null) {
  //     return this.addresses;
  //   }
  //   var addresses = await this.getAllAddresses();
  //   var streets = await this.getAllStreets();

  //   addresses.forEach((ad) => {
  //     ad.street = streets.find((element) => element.id === ad.street);
  //   });

  //   this.addresses = addresses;

  //   return this.addresses;
  // }

  // In Out History

  async allowEntrance(entrance_request, is_entrance) {
    const url = `${this.apiBaseUrl}/api/in-out/allow-entrance/`;
    const headers = this.getAuthorizationHeader();
    const data = {
      entrance_request: entrance_request.id,
      is_entrance: is_entrance,
    };
    const response = await axios.post(url, data, { headers });

    const responseData = await this.handleResponse(response);
    this._updateRequestById(entrance_request.id);

    return responseData;
  }

  async getRequestEntrances(entrance_request) {
    if (!entrance_request) {
      return;
    }
    const url = `${this.apiBaseUrl}/api/in-out/get-by-request/?entrance_request=${entrance_request.id}`;
    const headers = this.getAuthorizationHeader();
    const response = await axios.get(url, { headers });
    const responseData = await this.handleResponse(response);

    return responseData;
  }
}

export default HousingApi;
