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áginasize: tamanho da páginadataHora: 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
Errorse 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áginasize: 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
Errorse 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áriofirstname/lastname: Nome completo do usuárioemail: Email para login e comunicaçãouserImageUrl: Foto do perfil
Hierarquia
leaderId: ID do líder direto (null se não tem líder)leader: Nome do líder para exibiçãouserGroupId: Grupo de permissões do usuáriouserGroup: 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);