typescript
import {
AfterViewInit,
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
OnDestroy,
OnInit,
ViewChild,
ViewEncapsulation,
} from "@angular/core";
import {
FormBuilder,
FormControl,
FormGroup,
Validators,
} from "@angular/forms";
import { MatPaginator, PageEvent } from "@angular/material/paginator";
import { MatSort } from "@angular/material/sort";
import { Router } from "@angular/router";
import { fuseAnimations } from "@fuse/animations";
import { FuseConfirmationService } from "@fuse/services/confirmation";
import { FuseMediaWatcherService } from "@fuse/services/media-watcher";
import { NUMERO_INICIAL_PESQUISA } from "app/core/api/erp.api";
import { StateStorageService } from "app/core/auth/state-storage.service";
import { DefaultComponent } from "app/core/classes/default.component";
import { EnumService } from "app/modules/services/enum.service";
import {
debounceTime,
map,
merge,
Observable,
Subject,
switchMap,
takeUntil,
} from "rxjs";
import { UsuarioService } from "../usuario.service";
@Component({
selector: "usuario-list",
templateUrl: "./usuario-list.component.html",
styles: [
`
.usuario-grid {
grid-template-columns: 48px auto 40px;
@screen sm {
grid-template-columns: 48px auto 112px 72px;
}
@screen md {
grid-template-columns: 48px 112px auto 112px 72px;
}
@screen lg {
grid-template-columns: 48px 112px auto 112px 96px 96px 72px;
}
}
`,
],
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
animations: fuseAnimations,
})
export class UsuarioListComponent
extends DefaultComponent
implements OnInit, AfterViewInit, OnDestroy
{
@ViewChild(MatPaginator) private _paginator: MatPaginator;
@ViewChild(MatSort) private _sort: MatSort;
usuarios$: Observable<any[]>;
isLoading: boolean = false;
pagination: any;
searchInputControl: FormControl = new FormControl();
selectUsuario: any | null = null;
selectedUsuarioForm: FormGroup;
private _unsubscribeAll: Subject<any> = new Subject<any>();
nomePagina = "Usuário";
urlBase = "usuario";
perfisUsuario: any[] = [];
constructor(
protected router: Router,
protected stateStorageService: StateStorageService,
private _changeDetectorRef: ChangeDetectorRef,
private _fuseConfirmationService: FuseConfirmationService,
private _fuseMediaWatcherService: FuseMediaWatcherService,
private _formBuilder: FormBuilder,
private usuarioService: UsuarioService,
private enumService: EnumService
) {
super(router, stateStorageService);
}
async ngOnInit(): Promise<void> {
await super.ngOnInit();
this.selectedUsuarioForm = this._formBuilder.group({
idString: [],
nome: [, [Validators.required]],
email: [, [Validators.required]],
telefone: [, [Validators.required]],
celular: [, [Validators.required]],
senha: [, [Validators.required]],
confirmeSenha: [, [Validators.required]],
grupoAcesso: [, [Validators.required]],
});
this.usuarioService.pagination$
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((pagination: any) => {
this.pagination = pagination;
this._changeDetectorRef.markForCheck();
});
this.usuarios$ = this.usuarioService.usuarios$;
this.searchInputControl.valueChanges
.pipe(
takeUntil(this._unsubscribeAll),
debounceTime(300),
switchMap((query) => {
this.closeDetails();
this.isLoading = true;
return this.usuarioService.pesquisar(
0,
NUMERO_INICIAL_PESQUISA,
"nome",
"asc",
query
);
}),
map(() => (this.isLoading = false))
)
.subscribe();
await this.perfilUsuario();
}
async paginacao(event: PageEvent): Promise<void> {
this.paginar();
}
paginar() {
merge(this._sort.sortChange, this._paginator.page)
.pipe(
switchMap(() => {
this.closeDetails();
this.isLoading = true;
return this.usuarioService.pesquisar(
this._paginator.pageIndex,
this._paginator.pageSize,
this._sort.active,
this._sort.direction
);
}),
map(() => (this.isLoading = false))
)
.subscribe();
}
ngAfterViewInit(): void {
if (this._sort && this._paginator) {
this._sort.sort({
id: "nome",
start: "asc",
disableClear: true,
});
this._changeDetectorRef.markForCheck();
this._sort.sortChange
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(() => {
this._paginator.pageIndex = 0;
this.closeDetails();
});
merge(this._sort.sortChange, this._paginator.page)
.pipe(
switchMap(() => {
this.closeDetails();
this.isLoading = true;
return this.usuarioService.pesquisar(
this._paginator.pageIndex,
this._paginator.pageSize,
this._sort.active,
this._sort.direction
);
}),
map(() => (this.isLoading = false))
)
.subscribe();
}
}
ngOnDestroy(): void {
this._unsubscribeAll.next(null);
this._unsubscribeAll.complete();
}
adicionarUsuario() {
this.inserir = false;
this.usuarioService.criaUsuario().subscribe(
(usuario) => {
this.inserir = true;
this.selectUsuario = usuario;
this.selectedUsuarioForm.patchValue(usuario);
this._changeDetectorRef.markForCheck();
},
(err) => this.errorServiceS.error(err)
);
}
salvar() {
const usuario = this.selectedUsuarioForm.getRawValue();
this.usuarioService.salvar(usuario).subscribe(
(usuario) => {
this.selectUsuario = usuario;
this.selectedUsuarioForm.patchValue(usuario);
this._changeDetectorRef.markForCheck();
this.closeDetails();
},
(err) => this.errorServiceS.error(err)
);
}
visualizarUsuario(usuarioId: string): void {
this.inserir = false;
this.editar = false;
this.ver = false;
this.excluido = false;
if (this.selectUsuario && this.selectUsuario.idString === usuarioId) {
this.closeDetails();
return;
}
this.usuarioService.buscarUsuarioPorId(usuarioId).subscribe(
async (usuario) => {
this.ver = true;
this.selectUsuario = usuario;
this.selectedUsuarioForm.patchValue(usuario);
await this.ajusteTela();
},
(err) => this.errorServiceS.error(err)
);
}
async closeDetails(): Promise<void> {
this.selectUsuario = null;
this.inserir = false;
this.paginar();
await this.ajusteTela();
}
updateSelectedUsuario(): void {
const product = this.selectedUsuarioForm.getRawValue();
delete product.currentImageIndex;
this.usuarioService.updateProduct(product.id, product).subscribe(() => {});
}
ativarUsuario(idString: string): void {
const confirmation = this._fuseConfirmationService.open({
title: "Ativar usuários",
message: "Deseja ativar este usuário ?",
actions: {
confirm: {
label: "Ativar",
},
},
});
confirmation.afterClosed().subscribe((result) => {
if (result === "confirmed") {
this.usuarioService.ativarUsuario(idString).subscribe(
async () => await this.closeDetails(),
(err) => this.errorServiceS.error(err)
);
}
});
}
desativarUsuario(idString: string): void {
const confirmation = this._fuseConfirmationService.open({
title: "Desativar usuários",
message: "Deseja desativar este usuário ?",
actions: {
confirm: {
label: "Desativar",
},
},
});
confirmation.afterClosed().subscribe((result) => {
if (result === "confirmed") {
this.usuarioService.desativarUsuario(idString).subscribe(
async () => await this.closeDetails(),
(err) => this.errorServiceS.error(err)
);
}
});
}
private async ajusteTela() {
this._fuseMediaWatcherService.onMediaChange$
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(({}) => this._changeDetectorRef.markForCheck());
}
private async perfilUsuario(): Promise<any> {
this.perfisUsuario = [];
await this.enumService
.perfilUsuario()
.then((perfisUsuario) => (this.perfisUsuario = perfisUsuario))
.catch((erro) => this.errorServiceS.error(erro));
}
}
html
<div
class="sm:absolute sm:inset-0 flex flex-col flex-auto min-w-0 sm:overflow-hidden bg-card dark:bg-transparent"
>
<div
class="relative flex flex-col sm:flex-row flex-0 sm:items-center sm:justify-between py-8 px-6 md:px-8 border-b"
>
<div class="absolute inset-x-0 bottom-0" *ngIf="isLoading">
<mat-progress-bar [mode]="'indeterminate'"></mat-progress-bar>
</div>
<div class="text-4xl font-extrabold tracking-tight">{{ nomePagina }}</div>
<div class="flex flex-shrink-0 items-center mt-6 sm:mt-0 sm:ml-4">
<mat-form-field
*ngIf="podePesquisar"
class="fuse-mat-dense fuse-mat-no-subscript fuse-mat-rounded min-w-64"
pTooltip="Pesquisa {{ nomePagina }}"
>
<mat-icon
class="icon-size-5"
matPrefix
[svgIcon]="'heroicons_solid:search'"
></mat-icon>
<input
matInput
[formControl]="searchInputControl"
[autocomplete]="'off'"
/>
</mat-form-field>
<button
*ngIf="!inserir && podeIncluir"
class="ml-4"
mat-flat-button
[color]="'primary'"
(click)="adicionarUsuario()"
>
<mat-icon
[svgIcon]="'heroicons_outline:plus'"
pTooltip="Adicionar {{ nomePagina }}"
></mat-icon>
</button>
</div>
</div>
<div class="flex flex-auto overflow-hidden">
<div
class="flex flex-col flex-auto sm:mb-18 overflow-hidden sm:overflow-y-auto"
>
<ng-container *ngIf="usuarios$ | async as usuarios">
<ng-container *ngIf="usuarios.length > 0; else noUsuarios">
<div class="grid">
<div
class="usuario-grid z-10 sticky top-0 grid gap-4 py-4 px-6 md:px-8 shadow text-md font-semibold text-secondary bg-gray-50 dark:bg-black dark:bg-opacity-5"
matSort
matSortDisableClear
>
<div [mat-sort-header]="'nome'">Nome</div>
<div
[mat-sort-header]="'email'"
style="padding-left: 500px !important"
class="hidden lg:block"
>
E-mail
</div>
<div
[mat-sort-header]="'telefone'"
style="padding-left: 700px !important"
class="hidden lg:block"
>
Telefone
</div>
<div [mat-sort-header]="'celular'" class="hidden lg:block">
Celular
</div>
<div [mat-sort-header]="'grupoAcesso'" class="hidden lg:block">
Grupo de acesso
</div>
<div
[mat-sort-header]="'statusDoRegistro'"
class="hidden lg:block"
>
Status do registro
</div>
<div class="hidden sm:block">Ações</div>
</div>
<ng-container *ngIf="usuarios$ | async as usuarios">
<ng-container
*ngFor="let usuario of usuarios; trackBy: trackByFn"
>
<div
class="usuario-grid grid items-center gap-4 py-3 px-6 md:px-8 border-b"
*ngIf="usuario.email !== null"
>
<div class="min-w-100 lg:truncate">
{{ usuario.nome }}
</div>
<div
style="padding-left: 500px !important"
class="hidden lg:block min-w-100"
>
{{ usuario.email }}
</div>
<div
style="padding-left: 700px !important"
class="hidden lg:block min-w-100"
>
{{ usuario.telefone }}
</div>
<div class="hidden lg:block">
{{ usuario.celular }}
</div>
<div class="hidden lg:block">
{{ usuario.grupoAcessoDescricao }}
</div>
<div class="hidden lg:block">
<ng-container
*ngIf="usuario.statusDoRegistro.key === 'ATIVO'"
>
<mat-icon
class="text-green-400 icon-size-5"
[svgIcon]="'heroicons_solid:check'"
pTooltip="{{ usuario.statusDoRegistro.descricao }}"
></mat-icon>
</ng-container>
<ng-container
*ngIf="usuario.statusDoRegistro.key !== 'ATIVO'"
>
<mat-icon
class="text-gray-400 icon-size-5"
[svgIcon]="'heroicons_solid:x'"
pTooltip="{{ usuario.statusDoRegistro.descricao }}"
></mat-icon>
</ng-container>
</div>
<div *ngIf="usuario.idString !== undefined">
<button
*ngIf="podeVisualizar"
class="min-w-10 min-h-7 h-7 px-2 leading-6"
mat-stroked-button
(click)="visualizarUsuario(usuario.idString)"
>
<mat-icon
class="icon-size-5"
[pTooltip]="
selectUsuario?.idString === usuario.idString
? 'Voltar para a tela de pesquisa'
: 'Visualizar usuário'
"
[svgIcon]="
selectUsuario?.idString === usuario.idString
? 'heroicons_solid:chevron-up'
: 'heroicons_solid:chevron-down'
"
></mat-icon>
</button>
</div>
</div>
<div class="grid">
<ng-container
*ngIf="selectUsuario?.idString === usuario.idString"
>
<ng-container
*ngTemplateOutlet="
rowDetailsTemplate;
context: { $implicit: usuario }
"
></ng-container>
</ng-container>
</div>
</ng-container>
</ng-container>
</div>
<mat-paginator
class="sm:absolute sm:inset-x-0 sm:bottom-0 border-b sm:border-t sm:border-b-0 z-10 bg-gray-50 dark:bg-transparent"
[ngClass]="{ 'pointer-events-none': isLoading }"
[length]="pagination.totalElementos"
[pageIndex]="0"
[pageSize]="pagination.paginaTamanho"
[pageSizeOptions]="[5, 15, 25, 50, 75, 100, 500]"
[showFirstLastButtons]="true"
(page)="paginacao($event)"
></mat-paginator>
</ng-container>
</ng-container>
<ng-template #rowDetailsTemplate let-usuario>
<div class="shadow-lg overflow-hidden">
<div class="flex border-b">
<form
class="flex flex-col w-full"
[formGroup]="selectedUsuarioForm"
>
<div class="flex items-center">
<div style="padding-top: 10px; align-self: flex-end">
<button
class="ml-4"
mat-flat-button
[color]="'primary'"
(click)="closeDetails()"
pTooltip="Fechar tela"
>
<mat-icon
[svgIcon]="'heroicons_outline:arrow-down-tray'"
></mat-icon>
</button>
<button
*ngIf="!inserir && ver && podeAlterar"
class="ml-4"
mat-flat-button
[color]="'primary'"
(click)="alterar(rotaAtual)"
pTooltip="Alterar {{ nomePagina }}"
>
<mat-icon [svgIcon]="'heroicons_outline:pencil'"></mat-icon>
</button>
<button
*ngIf="!inserir && editar && podeVisualizar"
class="ml-4"
mat-flat-button
[color]="'primary'"
(click)="visualizar(rotaAtual)"
pTooltip="Visualizar {{ nomePagina }}"
>
<mat-icon [svgIcon]="'heroicons_outline:eye'"></mat-icon>
</button>
<button
*ngIf="
!inserir &&
ver &&
podeAtivarInativar &&
selectUsuario.statusDoRegistro.key === 'ATIVO'
"
class="ml-4"
mat-flat-button
[color]="'warn'"
(click)="desativarUsuario(selectUsuario.idString)"
pTooltip="Inativar {{ nomePagina }}"
>
<mat-icon
[svgIcon]="'heroicons_outline:hand-thumb-down'"
></mat-icon>
</button>
<button
*ngIf="
!inserir &&
ver &&
podeAtivarInativar &&
selectUsuario.statusDoRegistro.key !== 'ATIVO'
"
class="ml-4"
mat-flat-button
[color]="'accent'"
(click)="ativarUsuario(selectUsuario.idString)"
pTooltip="Ativar {{ nomePagina }}"
>
<mat-icon
[svgIcon]="'heroicons_outline:hand-thumb-up'"
></mat-icon>
</button>
<button
*ngIf="podeAlterar || podeIncluir"
class="ml-4"
mat-flat-button
[color]="'primary'"
(click)="salvar()"
pTooltip="Salvar {{ nomePagina }}"
>
<mat-icon [svgIcon]="'heroicons_outline:check'"></mat-icon>
</button>
</div>
</div>
<div class="flex flex-col p-8">
<div class="flex flex-auto flex-wrap">
<mat-form-field class="w-full">
<mat-label>Nome</mat-label>
<input matInput [formControlName]="'nome'" />
</mat-form-field>
</div>
<mat-form-field class="w-full">
<mat-label>E-mail</mat-label>
<input matInput [formControlName]="'email'" />
</mat-form-field>
<mat-form-field class="w-full">
<mat-label>Telefone</mat-label>
<input
matInput
[formControlName]="'telefone'"
[textMask]="{ mask: telefone }"
/>
</mat-form-field>
<mat-form-field class="w-full">
<mat-label>Celular</mat-label>
<input
matInput
[formControlName]="'celular'"
[textMask]="{ mask: MASKS.celular.textMask }"
/>
</mat-form-field>
<mat-form-field class="w-full">
<mat-label>Grupo de acesso</mat-label>
<mat-select [formControlName]="'grupoAcesso'">
<mat-option
*ngFor="let entidade of perfisUsuario"
[value]="entidade.key"
>{{ entidade.descricao }}</mat-option
>
</mat-select>
</mat-form-field>
<mat-form-field class="w-full" *ngIf="inserir">
<mat-label>Senha</mat-label>
<input matInput [formControlName]="'senha'" />
</mat-form-field>
<mat-form-field class="w-full" *ngIf="inserir">
<mat-label>Confirme a senha</mat-label>
<input matInput [formControlName]="'confirmeSenha'" />
</mat-form-field>
<div
class="sm:col-span-4 font-bold text-red-500"
*ngIf="inserir"
>
{{ informacaoSenha }}
</div>
</div>
</form>
</div>
</div>
</ng-template>
<ng-template #noUsuarios>
<div
class="p-8 sm:p-16 border-t text-4xl font-semibold tracking-tight text-center"
>
Não existe usuários
</div>
</ng-template>
</div>
</div>
</div>
1º) Quando clico na paginação a primeira vez ele não no banco de dados, fazer a paginação. Somente da segunda vez. Não consegui identificar o erro.
- Após fazer a ação de ativarUsuario e desativarUsuario, não está fazendo atualização a grade de pesquisa. Não consegui identificar o erro.