Portalweb/src/features/orders/api/order.service.ts

183 lines
5.6 KiB
TypeScript

import axios, {
AxiosError,
AxiosInstance,
InternalAxiosRequestConfig,
} from 'axios';
import {
getAccessToken,
handleTokenRefresh,
} from '../../login/utils/tokenRefresh';
import {
OrderFilters,
orderApiParamsSchema,
orderResponseSchema,
ordersResponseSchema,
storesResponseSchema,
customersResponseSchema,
sellersResponseSchema,
unwrapApiData,
} from '../schemas/order.schema';
import {
orderItemsResponseSchema,
OrderItem,
shipmentResponseSchema,
Shipment,
cargoMovementResponseSchema,
CargoMovement,
cuttingItemResponseSchema,
CuttingItem,
} from '../schemas/order.item.schema';
import { Store } from '../schemas/store.schema';
import { Seller } from '../schemas/seller.schema';
import { Order } from '../types';
const ORDERS_API_URL = process.env.NEXT_PUBLIC_ORDERS_API_URL;
export const ordersApi: AxiosInstance = axios.create({
baseURL: ORDERS_API_URL,
withCredentials: true,
headers: {
'Content-Type': 'application/json',
},
});
/**
* Adiciona o token de autenticação aos cabeçalhos da requisição.
* Executa apenas no ambiente do navegador (verifica a existência do objeto window).
*
* @param {InternalAxiosRequestConfig} config - A configuração da requisição Axios
* @returns {InternalAxiosRequestConfig} A configuração modificada com o cabeçalho Authorization
*/
const addToken = (config: InternalAxiosRequestConfig) => {
if (globalThis.window !== undefined) {
const token = getAccessToken();
if (token && config.headers) {
config.headers.Authorization = `Bearer ${token}`;
}
}
return config;
};
ordersApi.interceptors.request.use(addToken);
/**
* Trata erros de resposta das requisições da API.
* Tenta atualizar o token de autenticação se a requisição falhar.
*
* @param {AxiosError} error - O objeto de erro do Axios
* @returns {Promise} Resultado da tentativa de atualização do token
* @throws {AxiosError} Se não houver configuração de requisição original disponível
*/
const handleResponseError = async (error: AxiosError) => {
const originalRequest = error.config as InternalAxiosRequestConfig & {
_retry?: boolean;
};
if (!originalRequest) {
throw error;
}
return handleTokenRefresh(error, originalRequest, ordersApi);
};
ordersApi.interceptors.response.use(
(response) => response,
handleResponseError
);
export const orderService = {
/**
* Busca pedidos com base nos filtros fornecidos.
* Utiliza Zod para limpar e transformar os parâmetros automaticamente.
*
* @param {OrderFilters} filters - Critérios de filtro para buscar pedidos
* @returns {Promise<Order[]>} Array de pedidos que correspondem aos filtros
*/
findOrders: async (filters: OrderFilters): Promise<Order[]> => {
const cleanParams = orderApiParamsSchema.parse(filters);
const response = await ordersApi.get('/api/v1/orders/find', {
params: cleanParams,
});
return unwrapApiData(response, ordersResponseSchema, []);
},
/**
* Busca um pedido específico pelo seu ID.
*
* @param {number} id - O identificador único do pedido
* @returns {Promise<Order | null>} O pedido com o ID especificado, ou null se não encontrado
*/
findById: async (id: number): Promise<Order | null> => {
const response = await ordersApi.get(`/orders/${id}`);
return unwrapApiData(response, orderResponseSchema, null);
},
/**
* Recupera todas as lojas disponíveis.
*
* @returns {Promise<Store[]>} Array de todas as lojas, ou array vazio se nenhuma for encontrada
*/
findStores: async (): Promise<Store[]> => {
const response = await ordersApi.get('/api/v1/data-consult/stores');
return unwrapApiData(response, storesResponseSchema, []);
},
/**
* Busca clientes por nome.
* Retorna array vazio se o termo de busca tiver menos de 2 caracteres.
*
* @param {string} name - O nome do cliente a ser buscado (mínimo 2 caracteres)
* @returns {Promise<Array<{id: number, name: string, estcob: string}>>} Array de clientes correspondentes com os campos id, name e estcob
*/
findCustomers: async (
name: string
): Promise<Array<{ id: number; name: string; estcob: string }>> => {
if (!name || name.trim().length < 2) return [];
const response = await ordersApi.get(
`/api/v1/clientes/${encodeURIComponent(name)}`
);
return unwrapApiData(response, customersResponseSchema, []);
},
findSellers: async (): Promise<Seller[]> => {
const response = await ordersApi.get('/api/v1/data-consult/sellers');
return unwrapApiData(response, sellersResponseSchema, []);
},
findOrderItems: async (orderId: number): Promise<OrderItem[]> => {
const response = await ordersApi.get(`/api/v1/orders/itens/${orderId}`);
return unwrapApiData(response, orderItemsResponseSchema, []);
},
findDelivery: async (
orderId: number,
includeCompletedDeliveries: boolean = true
): Promise<Shipment[]> => {
const response = await ordersApi.get(
`/api/v1/orders/delivery/${orderId}`,
{
params: { includeCompletedDeliveries },
}
);
return unwrapApiData(response, shipmentResponseSchema, []);
},
findCargoMovement: async (orderId: number): Promise<CargoMovement[]> => {
const response = await ordersApi.get(
`/api/v1/orders/transfer/${orderId}`
);
return unwrapApiData(response, cargoMovementResponseSchema, []);
},
findCuttingItems: async (orderId: number): Promise<CuttingItem[]> => {
const response = await ordersApi.get(
`/api/v1/orders/cut-itens/${orderId}`
);
return unwrapApiData(response, cuttingItemResponseSchema, []);
},
};