mudanca requisicoes API do metodo PUT para POST e limpeza / organizacao dos códigos

This commit is contained in:
Vitex Tecnologia
2026-01-19 14:19:18 -03:00
parent 76cbd80eef
commit 71f9c9ab86
6 changed files with 68 additions and 311 deletions
+9 -100
View File
@@ -1,58 +1,32 @@
/**
* Serviço para integração com API do Asana
*/
/**
* Interface para workspace do Asana (resposta da API)
*/
export interface AsanaWorkspaceResponse {
gid: string;
resource_type: string;
name: string;
}
/**
* Interface para resposta da API de workspaces
*/
export interface AsanaWorkspacesResponse {
data: AsanaWorkspaceResponse[];
}
/**
* Interface para workspace formatado (usado no componente)
*/
export interface AsanaWorkspace {
id: string;
name: string;
}
/**
* Interface para usuário do Asana (resposta da API)
*/
export interface AsanaUserResponse {
gid: string;
name: string;
resource_type: string;
}
/**
* Interface para resposta da API de usuários
*/
export interface AsanaUsersResponse {
data: AsanaUserResponse[];
}
/**
* Interface para usuário formatado (usado no componente)
*/
export interface AsanaUser {
id: string;
name: string;
}
/**
* Interface para resposta da API de integração do Asana
*/
export interface AsanaIntegrationResponse {
success: boolean;
integracao_id?: string;
@@ -64,9 +38,6 @@ export interface AsanaIntegrationResponse {
usuario_asana_nome?: string;
}
/**
* Interface para request de criação/atualização de integração
*/
export interface AsanaIntegrationRequest {
user_id?: string;
api_key: string;
@@ -76,20 +47,9 @@ export interface AsanaIntegrationRequest {
usuario_asana_nome: string;
}
/**
* Serviço para integração com Asana
*/
class AsanaService {
private readonly BASE_URL = 'https://app.asana.com/api/1.0';
private readonly INTEGRATION_BASE_URL = 'https://prod-hgtx-intelligence-n8n.hgtx.com.br';
private readonly INTEGRATION_WEBHOOK_ID = 'c898beff-84cb-44df-a69c-6eff27ccd7aa';
private readonly ASANA_BASE_URL = 'https://app.asana.com/api/1.0';
/**
* Lista os workspaces do Asana usando o token fornecido
*
* @param token - Token de acesso do Asana
* @returns Promise com a lista de workspaces formatados
*/
async getWorkspaces(token: string): Promise<AsanaWorkspace[]> {
if (!token || token.trim().length === 0) {
throw {
@@ -107,12 +67,10 @@ class AsanaService {
};
const response = await axios.get<AsanaWorkspacesResponse>(
`${this.BASE_URL}/workspaces`,
`${this.ASANA_BASE_URL}/workspaces`,
{ headers }
);
// Converte a resposta da API para o formato esperado pelo componente
// A API retorna gid, mas o componente espera id
return response.data.data.map((workspace) => ({
id: workspace.gid,
name: workspace.name,
@@ -120,7 +78,6 @@ class AsanaService {
} catch (error: unknown) {
console.error('Erro ao buscar workspaces do Asana:', error);
// Retorna o erro da API se existir
if (error && typeof error === 'object' && 'response' in error) {
const axiosError = error as { response?: { data?: any; status?: number } };
@@ -146,13 +103,6 @@ class AsanaService {
}
}
/**
* Lista os usuários de um workspace do Asana
*
* @param token - Token de acesso do Asana
* @param workspaceId - ID do workspace (gid)
* @returns Promise com a lista de usuários formatados
*/
async getUsers(token: string, workspaceId: string): Promise<AsanaUser[]> {
if (!token || token.trim().length === 0) {
throw {
@@ -177,7 +127,7 @@ class AsanaService {
};
const response = await axios.get<AsanaUsersResponse>(
`${this.BASE_URL}/users?workspace=${workspaceId}`,
`${this.ASANA_BASE_URL}/users?workspace=${workspaceId}`,
{ headers }
);
@@ -190,7 +140,6 @@ class AsanaService {
} catch (error: unknown) {
console.error('Erro ao buscar usuários do Asana:', error);
// Retorna o erro da API se existir
if (error && typeof error === 'object' && 'response' in error) {
const axiosError = error as { response?: { data?: any; status?: number } };
@@ -216,12 +165,6 @@ class AsanaService {
}
}
/**
* Obtém os detalhes da integração do Asana do usuário
*
* @param userId - ID do usuário
* @returns Promise com os detalhes da integração ou null se não houver
*/
async getIntegration(userId: string): Promise<AsanaIntegrationResponse | null> {
if (!userId || userId.trim().length === 0) {
throw {
@@ -234,7 +177,6 @@ class AsanaService {
const axios = (await import('axios')).default;
const { GlobalFunctions } = await import('@/GlobalFunctions');
// Obtém o token JWT para autenticação
const token = await GlobalFunctions.getToken();
const apiKey = import.meta.env.VITE_API_KEY || '';
@@ -243,27 +185,19 @@ class AsanaService {
'accept': 'application/json',
};
// Adiciona API key (obrigatória)
if (apiKey) {
headers['apikey'] = apiKey;
}
// Adiciona token JWT se disponível
if (token) {
headers['Authorization'] = `Bearer ${token}`;
}
// Em desenvolvimento, usa proxy do Vite para evitar CORS
const baseUrl = import.meta.env.DEV
? '/api/intelligence'
: this.INTEGRATION_BASE_URL;
const response = await axios.get<AsanaIntegrationResponse>(
`${baseUrl}/webhook/${this.INTEGRATION_WEBHOOK_ID}/codex/agente-pessoal/integracoes/asana/${userId}`,
`https://prod-hgtx-intelligence-n8n.hgtx.com.br/webhook/c898beff-84cb-44df-a69c-6eff27ccd7aa/codex/agente-pessoal/integracoes/asana/${userId}`,
{ headers }
);
// Se success é false, retorna null (não tem integração)
if (!response.data.success) {
return null;
}
@@ -280,17 +214,10 @@ class AsanaService {
}
}
// Para outros erros, retorna null silenciosamente (não quebra a aplicação)
return null;
}
}
/**
* Cria uma nova integração do Asana
*
* @param request - Dados da integração a ser criada
* @returns Promise com a resposta da criação
*/
async createIntegration(request: AsanaIntegrationRequest): Promise<AsanaIntegrationResponse> {
if (!request.user_id || !request.api_key || !request.workspace_gid || !request.usuario_asana_gid) {
throw {
@@ -322,13 +249,8 @@ class AsanaService {
headers['Authorization'] = `Bearer ${token}`;
}
// Em desenvolvimento, usa proxy do Vite para evitar CORS
const baseUrl = import.meta.env.DEV
? '/api/intelligence'
: this.INTEGRATION_BASE_URL;
const response = await axios.post<AsanaIntegrationResponse>(
`${baseUrl}/webhook/codex/agente-pessoal/integracoes/asana`,
`https://prod-hgtx-intelligence-n8n.hgtx.com.br/webhook/codex/agente-pessoal/integracoes/asana`,
request,
{ headers }
);
@@ -357,13 +279,6 @@ class AsanaService {
}
}
/**
* Atualiza uma integração existente do Asana
*
* @param integracaoId - ID da integração a ser atualizada
* @param request - Dados da integração a ser atualizada
* @returns Promise com a resposta da atualização
*/
async updateIntegration(integracaoId: string, request: Omit<AsanaIntegrationRequest, 'user_id'>): Promise<AsanaIntegrationResponse> {
if (!integracaoId || !request.api_key || !request.workspace_gid || !request.usuario_asana_gid) {
throw {
@@ -376,7 +291,6 @@ class AsanaService {
const axios = (await import('axios')).default;
const { GlobalFunctions } = await import('@/GlobalFunctions');
// Obtém o token JWT para autenticação
const token = await GlobalFunctions.getToken();
const apiKey = import.meta.env.VITE_API_KEY || '';
@@ -385,23 +299,18 @@ class AsanaService {
'accept': 'application/json',
};
// Adiciona API key (obrigatória)
if (apiKey) {
headers['apikey'] = apiKey;
}
// Adiciona token JWT se disponível
if (token) {
headers['Authorization'] = `Bearer ${token}`;
}
// Em desenvolvimento, usa proxy do Vite para evitar CORS
const baseUrl = import.meta.env.DEV
? '/api/intelligence'
: this.INTEGRATION_BASE_URL;
const response = await axios.put<AsanaIntegrationResponse>(
`${baseUrl}/webhook/${this.INTEGRATION_WEBHOOK_ID}/codex/agente-pessoal/integracoes/asana/${integracaoId}`,
const url = `https://prod-hgtx-intelligence-n8n.hgtx.com.br/webhook/c898beff-84cb-44df-a69c-6eff27ccd7aa/codex/agente-pessoal/integracoes/asana/${integracaoId}`;
const response = await axios.post<AsanaIntegrationResponse>(
url,
request,
{ headers }
);
+2 -2
View File
@@ -6,7 +6,7 @@ export { apiService } from './api';
export { transcriptionService } from './transcription';
export { audioGenerationService, VOICE_OPTIONS } from './audioGeneration';
export { imageGenerationService, IMAGE_SIZE_OPTIONS } from './imageGeneration';
export { userProfileService } from './userProfile';
export { personalAgent } from './personalAgent';
export { asanaService } from './asana';
export type { TranscriptionResponse, TranscriptionRequest } from './transcription';
export type { AudioGenerationResponse, AudioGenerationRequest, VoiceType } from './audioGeneration';
@@ -20,7 +20,7 @@ export type {
ExpensesResponse,
ExpensesFilters,
ExpenseCategory
} from './userProfile';
} from './personalAgent';
export type {
AsanaWorkspace,
AsanaWorkspaceResponse,
@@ -1,9 +1,4 @@
import { apiService } from './api';
import { GlobalFunctions } from '@/GlobalFunctions';
/**
* Interfaces para o serviço de perfil do usuário
*/
export interface UserProfile {
success: boolean;
id?: string;
@@ -27,9 +22,6 @@ export interface UpdateUserRequest {
followup: boolean;
}
/**
* Interface para indicadores financeiros
*/
export interface FinancialIndicators {
success: boolean;
id: string;
@@ -41,9 +33,6 @@ export interface FinancialIndicators {
message?: string;
}
/**
* Interface para despesa individual da API
*/
export interface ExpenseItem {
id: string;
data_hora: string;
@@ -56,9 +45,6 @@ export interface ExpenseItem {
usuario_email: string;
}
/**
* Interface para resposta da API de despesas
*/
export interface ExpensesResponse {
success: boolean;
total_registros: number;
@@ -68,9 +54,6 @@ export interface ExpensesResponse {
data: ExpenseItem[];
}
/**
* Interface para filtros de busca de despesas
*/
export interface ExpensesFilters {
page?: number;
per_page?: number;
@@ -80,9 +63,6 @@ export interface ExpensesFilters {
data_final?: string;
}
/**
* Interface para categoria de despesas
*/
export interface ExpenseCategory {
id: number;
nome: string;
@@ -91,29 +71,8 @@ export interface ExpenseCategory {
atualizado_em: string;
}
/**
* Serviço para gerenciamento de perfil do usuário
*/
class UserProfileService {
// Em desenvolvimento, usa proxy do Vite para evitar CORS
// Em produção, usa URL direta (requer que servidor permita PUT no CORS)
private readonly BASE_URL = import.meta.env.DEV
? '/api/intelligence'
: 'https://prod-hgtx-intelligence-n8n.hgtx.com.br';
private readonly WEBHOOK_ID = '2299acaf-70ee-47e3-a6fc-56dcc678d651';
private readonly GET_USER_ENDPOINT = `${this.BASE_URL}/webhook/${this.WEBHOOK_ID}/codex/agente-pessoal/user`;
private readonly CREATE_USER_ENDPOINT = `${this.BASE_URL}/webhook/codex/agente-pessoal/user`;
private readonly UPDATE_USER_ENDPOINT = `${this.BASE_URL}/webhook/${this.WEBHOOK_ID}/codex/agente-pessoal/user`;
private readonly GET_FINANCIAL_INDICATORS_ENDPOINT = `${this.BASE_URL}/webhook/${this.WEBHOOK_ID}/codex/agente-pessoal/financas/indicadores`;
private readonly GET_EXPENSES_ENDPOINT = `${this.BASE_URL}/webhook/${this.WEBHOOK_ID}/codex/agente-pessoal/financas`;
private readonly GET_CATEGORIES_ENDPOINT = `${this.BASE_URL}/webhook/codex/agente-pessoal/categorias`;
class PersonalAgent {
/**
* Obtém os detalhes do usuário pelo email
*
* @param userEmail - Email do usuário (opcional, usa do GlobalFunctions se não fornecido)
* @returns Promise com os dados do usuário ou erro se não existir
*/
async getUserProfile(userEmail?: string): Promise<UserProfile> {
const email = userEmail || GlobalFunctions.getUsuarioLogado().email;
@@ -125,36 +84,30 @@ class UserProfileService {
}
try {
// Usa axios diretamente pois a URL é absoluta e diferente do baseURL
const axios = (await import('axios')).default;
// Obtém o token JWT para autenticação
const token = await GlobalFunctions.getToken();
const apiKey = import.meta.env.VITE_API_KEY || '';
// Prepara headers de autenticação
const headers: Record<string, string> = {
'Content-Type': 'application/json',
};
// Adiciona API key (obrigatória)
if (apiKey) {
headers['apikey'] = apiKey;
}
// Adiciona token JWT se disponível
if (token) {
headers['Authorization'] = `Bearer ${token}`;
}
const response = await axios.get<UserProfile>(
`${this.GET_USER_ENDPOINT}/${email}`,
`https://prod-hgtx-intelligence-n8n.hgtx.com.br/webhook/2299acaf-70ee-47e3-a6fc-56dcc678d651/codex/agente-pessoal/user/${email}`,
{ headers }
);
return response.data;
} catch (error: any) {
// Se o usuário não existir, retorna o erro da API
if (error.response?.data) {
return error.response.data;
}
@@ -167,14 +120,8 @@ class UserProfileService {
}
}
/**
* Cria um novo usuário
*
* @param request - Dados do usuário a ser criado
* @returns Promise com os dados do usuário criado
*/
async createUser(request: CreateUserRequest): Promise<UserProfile> {
// Validações
if (!request.nome || request.nome.trim().length === 0) {
throw {
success: false,
@@ -196,48 +143,30 @@ class UserProfileService {
};
}
// Remove formatação do WhatsApp (apenas números)
const whatsappNumbers = request.whatsapp.replace(/\D/g, '');
try {
const axios = (await import('axios')).default;
// Obtém o token JWT para autenticação
const token = await GlobalFunctions.getToken();
const apiKey = import.meta.env.VITE_API_KEY || '';
// Prepara headers de autenticação
// A API pode precisar apenas da apikey, não do token JWT
const headers: Record<string, string> = {
'Content-Type': 'application/json',
};
// Adiciona API key (obrigatória)
if (apiKey) {
headers['apikey'] = apiKey;
} else {
console.warn('VITE_API_KEY não configurada');
console.warn('API_KEY não configurada');
}
// Adiciona token JWT se disponível (pode ser necessário)
if (token) {
headers['Authorization'] = `Bearer ${token}`;
}
console.log('Criando usuário:', {
url: this.CREATE_USER_ENDPOINT,
hasApiKey: !!apiKey,
hasToken: !!token,
data: {
nome: request.nome.trim(),
email: request.email.trim(),
whatsapp: whatsappNumbers,
followup: request.followup,
},
});
const response = await axios.post<UserProfile>(
this.CREATE_USER_ENDPOINT,
'https://prod-hgtx-intelligence-n8n.hgtx.com.br/webhook/codex/agente-pessoal/user',
{
nome: request.nome.trim(),
email: request.email.trim(),
@@ -249,7 +178,6 @@ class UserProfileService {
return response.data;
} catch (error: any) {
// Retorna o erro da API se existir
if (error.response?.data) {
throw error.response.data;
}
@@ -262,15 +190,8 @@ class UserProfileService {
}
}
/**
* Atualiza os dados do usuário
*
* @param userId - ID do usuário
* @param request - Dados a serem atualizados
* @returns Promise com os dados atualizados do usuário
*/
async updateUser(userId: string, request: UpdateUserRequest): Promise<UserProfile> {
// Validações
if (!userId || userId.trim().length === 0) {
throw {
success: false,
@@ -292,47 +213,28 @@ class UserProfileService {
};
}
// Remove formatação do WhatsApp (apenas números)
const whatsappNumbers = request.whatsapp.replace(/\D/g, '');
try {
const axios = (await import('axios')).default;
// Obtém o token JWT para autenticação
const token = await GlobalFunctions.getToken();
const apiKey = import.meta.env.VITE_API_KEY || '';
// Prepara headers de autenticação
const headers: Record<string, string> = {
'Content-Type': 'application/json',
};
// Adiciona API key (obrigatória)
if (apiKey) {
headers['apikey'] = apiKey;
}
// Adiciona token JWT se disponível
if (token) {
headers['Authorization'] = `Bearer ${token}`;
}
console.log('Atualizando usuário:', {
url: `${this.UPDATE_USER_ENDPOINT}/${userId}`,
method: 'PUT',
hasApiKey: !!apiKey,
hasToken: !!token,
isDev: import.meta.env.DEV,
data: {
nome: request.nome.trim(),
whatsapp: whatsappNumbers,
followup: request.followup,
},
});
// Usa PUT conforme documentação da API
const response = await axios.put<UserProfile>(
`${this.UPDATE_USER_ENDPOINT}/${userId}`,
const response = await axios.post<UserProfile>(
`https://prod-hgtx-intelligence-n8n.hgtx.com.br/webhook/2299acaf-70ee-47e3-a6fc-56dcc678d651/codex/agente-pessoal/user/${userId}`,
{
nome: request.nome.trim(),
whatsapp: whatsappNumbers,
@@ -343,7 +245,6 @@ class UserProfileService {
return response.data;
} catch (error: any) {
// Retorna o erro da API se existir
if (error.response?.data) {
throw error.response.data;
}
@@ -356,12 +257,6 @@ class UserProfileService {
}
}
/**
* Obtém os indicadores financeiros do usuário
*
* @param userEmail - Email do usuário (opcional, usa do GlobalFunctions se não fornecido)
* @returns Promise com os indicadores financeiros
*/
async getFinancialIndicators(userEmail?: string): Promise<FinancialIndicators> {
const email = userEmail || GlobalFunctions.getUsuarioLogado().email;
@@ -374,34 +269,29 @@ class UserProfileService {
try {
const axios = (await import('axios')).default;
// Obtém o token JWT para autenticação
const token = await GlobalFunctions.getToken();
const apiKey = import.meta.env.VITE_API_KEY || '';
// Prepara headers de autenticação
const headers: Record<string, string> = {
'Content-Type': 'application/json',
};
// Adiciona API key (obrigatória)
if (apiKey) {
headers['apikey'] = apiKey;
}
// Adiciona token JWT se disponível
if (token) {
headers['Authorization'] = `Bearer ${token}`;
}
const response = await axios.get<FinancialIndicators>(
`${this.GET_FINANCIAL_INDICATORS_ENDPOINT}/${email}`,
`https://prod-hgtx-intelligence-n8n.hgtx.com.br/webhook/2299acaf-70ee-47e3-a6fc-56dcc678d651/codex/agente-pessoal/financas/indicadores/${email}`,
{ headers }
);
return response.data;
} catch (error: unknown) {
// Retorna o erro da API se existir
if (error && typeof error === 'object' && 'response' in error) {
const axiosError = error as { response?: { data?: FinancialIndicators } };
if (axiosError.response?.data) {
@@ -412,20 +302,13 @@ class UserProfileService {
throw {
success: false,
message: error instanceof Error ? error.message : 'Erro ao buscar indicadores financeiros',
status: error && typeof error === 'object' && 'response' in error
? (error as { response?: { status?: number } }).response?.status
status: error && typeof error === 'object' && 'response' in error
? (error as { response?: { status?: number } }).response?.status
: undefined,
};
}
}
/**
* Obtém a lista de despesas do usuário com paginação e filtros
*
* @param userEmail - Email do usuário (opcional, usa do GlobalFunctions se não fornecido)
* @param filters - Filtros de busca (página, itens por página, descrição, categoria, datas)
* @returns Promise com a lista de despesas paginada
*/
async getExpenses(userEmail?: string, filters?: ExpensesFilters): Promise<ExpensesResponse> {
const email = userEmail || GlobalFunctions.getUsuarioLogado().email;
@@ -438,22 +321,18 @@ class UserProfileService {
try {
const axios = (await import('axios')).default;
// Obtém o token JWT para autenticação
const token = await GlobalFunctions.getToken();
const apiKey = import.meta.env.VITE_API_KEY || '';
// Prepara headers de autenticação
const headers: Record<string, string> = {
'Content-Type': 'application/json',
};
// Adiciona API key (obrigatória)
if (apiKey) {
headers['apikey'] = apiKey;
}
// Adiciona token JWT se disponível
if (token) {
headers['Authorization'] = `Bearer ${token}`;
}
@@ -468,14 +347,13 @@ class UserProfileService {
if (filters?.data_final) params.append('data_final', filters.data_final);
const queryString = params.toString();
const url = `${this.GET_EXPENSES_ENDPOINT}/${email}${queryString ? `?${queryString}` : ''}`;
const url = `https://prod-hgtx-intelligence-n8n.hgtx.com.br/webhook/2299acaf-70ee-47e3-a6fc-56dcc678d651/codex/agente-pessoal/financas/${email}${queryString ? `?${queryString}` : ''}`;
const response = await axios.get<ExpensesResponse[]>(url, { headers });
// A API retorna um array com um único objeto
if (Array.isArray(response.data) && response.data.length > 0) {
const expensesResponse = response.data[0];
// Valida e limpa o array de dados, removendo objetos vazios
if (expensesResponse.data && Array.isArray(expensesResponse.data)) {
// Filtra objetos vazios (sem propriedades ou apenas com propriedades vazias)
@@ -483,7 +361,7 @@ class UserProfileService {
// Verifica se o objeto tem pelo menos uma propriedade válida
return item && typeof item === 'object' && Object.keys(item).length > 0 && item.id;
});
// Se após filtrar não há dados, garante que data seja um array vazio
if (expensesResponse.data.length === 0) {
expensesResponse.data = [];
@@ -496,7 +374,7 @@ class UserProfileService {
expensesResponse.total_registros = 0;
expensesResponse.total_paginas = 0;
}
return expensesResponse;
}
@@ -521,42 +399,33 @@ class UserProfileService {
throw {
success: false,
message: error instanceof Error ? error.message : 'Erro ao buscar despesas',
status: error && typeof error === 'object' && 'response' in error
? (error as { response?: { status?: number } }).response?.status
status: error && typeof error === 'object' && 'response' in error
? (error as { response?: { status?: number } }).response?.status
: undefined,
};
}
}
/**
* Obtém a lista de categorias de despesas
*
* @returns Promise com a lista de categorias
*/
async getCategories(): Promise<ExpenseCategory[]> {
try {
const axios = (await import('axios')).default;
// Obtém o token JWT para autenticação
const token = await GlobalFunctions.getToken();
const apiKey = import.meta.env.VITE_API_KEY || '';
// Prepara headers de autenticação
const headers: Record<string, string> = {
'Content-Type': 'application/json',
};
// Adiciona API key (obrigatória)
if (apiKey) {
headers['apikey'] = apiKey;
}
// Adiciona token JWT se disponível
if (token) {
headers['Authorization'] = `Bearer ${token}`;
}
const response = await axios.get<ExpenseCategory[]>(this.GET_CATEGORIES_ENDPOINT, { headers });
const response = await axios.get<ExpenseCategory[]>('https://prod-hgtx-intelligence-n8n.hgtx.com.br/webhook/codex/agente-pessoal/categorias', { headers });
// A API retorna um array de categorias
if (Array.isArray(response.data)) {
@@ -566,12 +435,10 @@ class UserProfileService {
return [];
} catch (error: unknown) {
console.error('Erro ao buscar categorias:', error);
// Retorna array vazio em caso de erro para não quebrar a aplicação
return [];
}
}
}
// Exporta instância única (Singleton)
export const userProfileService = new UserProfileService();
export const personalAgent = new PersonalAgent();