Pular para o conteúdo principal

User Service

Gerencia operações relacionadas aos usuários do sistema, permitindo buscar lista completa de usuários e consultar subordinados de um líder específico.

Visão Geral

O UserService é responsável por:

  • Buscar usuários da API remota
  • Listar subordinados de um líder
  • Fornecer informações de perfil e hierarquia
  • Acessar dados de organizações vinculadas
  • Consultar clientes atribuídos ao usuário
  • Listar colaboradores do usuário

Os usuários representam os membros da equipe que utilizam o sistema, contendo informações de perfil, hierarquia organizacional e atribuições comerciais.

Localização: services/user/user.service.ts

Endpoints Utilizados

Base URL

Todos os endpoints são relativos à base URL configurada em services/api.service.ts

Métodos

fetchRemote(params)

Busca todos os usuários do sistema com paginação.

Endpoint: GET /usuario/usuarios

Parâmetros:

type FetchUsersParams = {
page?: number; // Número da página (padrão: 0)
size?: number; // Quantidade de itens por página (padrão: 999)
dataHora?: string; // Timestamp para sincronização incremental (futuro)
};

Query Params enviados:

  • page: número da página
  • size: tamanho da página
  • dataHora: timestamp (opcional)

Retorno:

Promise<User[]>;

Exemplo de uso:

import { userService } from "@/services/user/user.service.instance";

// Buscar todos os usuários
const allUsers = await userService.fetchRemote();

// Buscar com paginação
const usersPage = await userService.fetchRemote({
page: 0,
size: 50,
});

// Buscar para sincronização
const users = await userService.fetchRemote({
dataHora: "2026-02-27T10:00:00Z",
});

Tratamento de erros:

  • Lança Error se o status da resposta não for 2xx
  • Mensagem: UserService.fetchRemote failed: {status}

fetchRemoteByLeaderId(params)

Busca subordinados de um líder específico.

Endpoint: GET /usuario/listarSubordinados/{leaderId}

Parâmetros:

type FetchUsersByLeaderIdParams = {
leaderId: string; // ID do líder (obrigatório)
page?: number; // Número da página (padrão: 0)
size?: number; // Quantidade de itens por página (padrão: 999)
};

Path Params:

  • leaderId: ID do líder

Query Params enviados:

  • page: número da página
  • size: tamanho da página

Retorno:

Promise<User[]>;

Exemplo de uso:

// Buscar subordinados de um líder
const teamMembers = await userService.fetchRemoteByLeaderId({
leaderId: "user-001",
});

console.log(`Líder tem ${teamMembers.length} subordinados`);

// Buscar com paginação
const teamPage = await userService.fetchRemoteByLeaderId({
leaderId: "user-001",
page: 0,
size: 20,
});

Tratamento de erros:

  • Lança Error se o status da resposta não for 2xx
  • Mensagem: UserService.fetchRemoteByLeaderId failed: {status}

Estruturas de Dados

Interface User

interface User {
// Identificação
id: string; // ID único do usuário
firstname: string; // Primeiro nome
lastname: string; // Sobrenome
email: string; // Email do usuário

// Imagem
userImageUrl: string | null; // URL da foto do usuário
userImageKey: string | null; // Chave da imagem

// Grupo e Permissões
userGroupId: string | null; // ID do grupo de usuários
userGroup: string | null; // Nome do grupo

// Hierarquia
leaderId: string | null; // ID do líder
leader: string | null; // Nome do líder

// Organizações
organizations: Array<{
id: string; // ID da organização
name: string; // Nome da organização
}>;

// Clientes Atribuídos
clients: Array<
Pick<
Client,
| "id"
| "nomeFantasia"
| "tipoPessoa"
| "email"
| "telefone"
| "uf"
| "nomeCidade"
>
>;

// Colaboradores
collaborators: Array<{
id: string; // ID do colaborador
nome: string; // Nome
SobreNome: string; // Sobrenome
userImageUrl: string; // URL da imagem
userImageKey: string; // Chave da imagem
}>;
}

Campos Importantes

Identificação e Perfil

  • id: Identificador único do usuário
  • firstname / lastname: Nome completo do usuário
  • email: Email para login e comunicação
  • userImageUrl: Foto do perfil

Hierarquia

  • leaderId: ID do líder direto (null se não tem líder)
  • leader: Nome do líder para exibição
  • userGroupId: Grupo de permissões do usuário
  • userGroup: Nome do grupo (ex: "Administradores", "Vendas")

Organizações

  • organizations: Lista de organizações às quais o usuário pertence
  • Usuário pode estar em múltiplas organizações

Clientes

  • clients: Lista de clientes atribuídos ao usuário
  • Útil para filtrar vendas e relatórios por carteira

Colaboradores

  • collaborators: Lista de colaboradores relacionados
  • Pode representar equipe ou assistentes

Componentes Relacionados

buildQueryParams Helper

Função utilitária que converte objeto de parâmetros em URLSearchParams.

Localização: helpers/buildQueryParams.ts

PageResponse Interface

Interface compartilhada para respostas paginadas.

Localização: services/client/client.service.ts

interface PageResponse<T> {
content: T[]; // Array de itens da página
page?: number; // Número da página atual
size?: number; // Tamanho da página
totalPages?: number; // Total de páginas
totalElements?: number; // Total de elementos
}

Casos de Uso

Listar Todos os Usuários

// Obter lista completa de usuários
async function getAllUsers() {
const users = await userService.fetchRemote();

console.log(`Total de usuários: ${users.length}`);

// Agrupar por grupo
const byGroup = users.reduce(
(acc, user) => {
const group = user.userGroup || "Sem Grupo";
if (!acc[group]) {
acc[group] = [];
}
acc[group].push(user);
return acc;
},
{} as Record<string, User[]>,
);

console.log("\nUsuários por Grupo:");
Object.entries(byGroup).forEach(([group, members]) => {
console.log(`${group}: ${members.length} usuários`);
});

return users;
}

await getAllUsers();

Buscar Equipe de um Líder

// Listar subordinados diretos
async function getTeamMembers(leaderId: string) {
const team = await userService.fetchRemoteByLeaderId({ leaderId });

console.log(`Equipe do líder ${leaderId}:`);
team.forEach((member) => {
console.log(
` - ${member.firstname} ${member.lastname} (${member.userGroup})`,
);
console.log(` Email: ${member.email}`);
console.log(` Clientes: ${member.clients.length}`);
});

return team;
}

// Exemplo de uso
const team = await getTeamMembers("user-001");

Renderizar Select de Vendedores

// Gerar opções para select de vendedores
async function getSellerOptions() {
const users = await userService.fetchRemote();

// Filtrar apenas vendedores
const sellers = users.filter((user) =>
user.userGroup?.toLowerCase().includes("venda"),
);

// Gerar opções
const options = sellers.map((seller) => ({
value: seller.id,
label: `${seller.firstname} ${seller.lastname}`,
email: seller.email,
clientCount: seller.clients.length,
imageUrl: seller.userImageUrl,
}));

// Ordenar por nome
options.sort((a, b) => a.label.localeCompare(b.label));

return options;
}

// Exemplo de uso em componente
const sellerOptions = await getSellerOptions();
console.log("Vendedores disponíveis:");
sellerOptions.forEach((option) => {
console.log(` ${option.label} - ${option.clientCount} clientes`);
});

Testes

Localização

services/user/user.service.test.ts

Executar Testes

# Teste específico do serviço
npx jest services/user/user.service.test.ts

# Modo watch
npx jest services/user/user.service.test.ts --watch

# Com coverage
npx jest services/user/user.service.test.ts --coverage

Casos de Teste

  • fetchRemote: busca de usuários com paginação
  • fetchRemote: retorna content em status 2xx
  • fetchRemote: tratamento de erros para status não-2xx
  • fetchRemoteByLeaderId: busca subordinados por ID do líder
  • fetchRemoteByLeaderId: retorna content em status 2xx
  • fetchRemoteByLeaderId: tratamento de erros para status não-2xx
  • fetchRemoteByLeaderId: chama endpoint com parâmetro correto

Mocks

Localização

__mocks__/user.mock.ts

Dados Disponíveis

Mock com 10 usuários de exemplo:

  • Usuários com e sem líder
  • Diferentes grupos (Administradores, Vendas, Financeiro, etc)
  • Usuários com e sem imagem
  • Usuários com clientes atribuídos
  • Diferentes organizações
  • Resposta paginada

Exemplo de uso em testes:

import { userResponseMock } from "@/__mocks__/user.mock";

// Mock fetchRemote
const apiWithoutAccessToken: any = {
get: jest.fn(async () => ({
status: 200,
data: userResponseMock,
})),
};

const service = new UserService({ apiWithoutAccessToken });
const result = await service.fetchRemote();

expect(result).toEqual(userResponseMock.content);