first commit

This commit is contained in:
OnlyPapy98
2025-12-16 14:20:02 +01:00
commit dde2e8aebf
320 changed files with 30462 additions and 0 deletions

View File

@@ -0,0 +1,41 @@
<div class="flex flex-col gap-2 min-h-screen">
<div class="flex items-center justify-between">
<h2 class="text-2xl font-semibold text-gray-900 dark:text-gray-100">
La liste des utilisateurs
</h2>
<z-button (click)="openCreate()">Nouvel utilisateur</z-button>
</div>
<app-search-bar (search)="onSearch($event)"></app-search-bar>
<app-data-table [data]="rows()" [columns]="cols" [sort]="sort()" (sortChange)="sort.set($event)">
<ng-template #rowActions let-row>
<div class="flex gap-3">
<button z-button zType="ghost" (click)="openEdit(row)"><i class="icon-pen"></i></button>
<button z-button zType="destructive" (click)="remove(row)">
<i class="icon-trash"></i>
</button>
</div>
</ng-template>
</app-data-table>
<app-paginator
[total]="total()"
[page]="page()"
[perPage]="perPage()"
(pageChange)="page.set($event)"
(perPageChange)="perPage.set($event)"
></app-paginator>
</div>
<app-modal [open]="modalOpen()" [title]="modalTitle()" (close)="closeModal()" size="xl">
<app-user-form
[value]="editingItem() ?? undefined"
(save)="onFormSave($event)"
(cancel)="closeModal()"
/>
<div modal-actions class="flex justify-end gap-2">
<z-button zType="destructive" (click)="closeModal()">Annuler</z-button>
<z-button zType="default" (click)="submitChildForm()">Enregistrer</z-button>
</div>
</app-modal>

View File

@@ -0,0 +1,198 @@
import { CommonModule } from '@angular/common';
import {
ChangeDetectionStrategy,
Component,
ViewChild,
signal,
effect,
untracked,
} from '@angular/core';
import { DataTable, TableColumn, SortState } from '@shared/components/data-table/data-table';
import { Paginator } from '@shared/components/paginator/paginator';
import { SearchBar } from '@shared/components/search-bar/search-bar';
import { Modal } from '@shared/components/modal/modal';
import { ZardButtonComponent } from '@shared/components/button/button.component';
import { SortDir } from '@shared/paging/paging';
import { User } from 'src/app/core/interfaces/user';
import { UserService } from 'src/app/core/services/user';
import { Role } from 'src/app/core/interfaces/role';
import { RoleService } from 'src/app/core/services/role';
import { UserForm } from '@shared/forms/user-form/user-form';
import { toast } from 'ngx-sonner';
@Component({
standalone: true,
selector: 'app-users',
templateUrl: './users.html',
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [CommonModule, DataTable, Paginator, SearchBar, Modal, ZardButtonComponent, UserForm],
})
export class UsersPage {
rows = signal<User[]>([]);
total = signal(0);
loading = signal(false);
roleMap = new Map<string, string>();
page = signal(1);
perPage = signal(10);
search = signal('');
sort = signal<SortState>({ key: 'nom', dir: 'asc' });
modalOpen = signal(false);
modalTitle = signal('Nouvel utilisateur');
editingItem = signal<User | null>(null);
@ViewChild(UserForm) formComp?: UserForm;
cols: TableColumn<User>[] = [
{ key: 'nom', label: 'Nom', sortable: true },
{ key: 'prenom', label: 'Prénom', sortable: true },
{ key: 'identifiant', label: 'Identifiant', sortable: true },
{ key: 'matriculeAgent', label: 'Matricule', sortable: true },
{
key: 'role.name',
label: 'Rôle',
sortable: true,
cell: (u) => this.roleMap.get(u.roleId) ?? u.role?.name ?? '—',
},
{ key: 'statut', label: 'Statut', sortable: true },
{
key: 'derniereConnexion',
label: 'Dernière connexion',
cell: (u) =>
u.derniereConnexion ? new Date(u.derniereConnexion).toLocaleDateString('fr-FR') : '—',
},
{
key: 'restrictionConnexion',
label: 'Restr. Conn.',
cell: (u) => String(u.restrictionConnexion),
},
{
key: 'restrictionAutomatique',
label: 'Restr. Auto',
cell: (u) => String(u.restrictionAutomatique),
},
{ key: 'nombreIpAutorise', label: 'IP Autorisé' },
{ key: 'nombreIpAutoAutorise', label: 'IP Auto' },
];
constructor(private api: UserService, private roleService: RoleService) {
this.roleService
.list({ page: 1, perPage: 100, search: '', sortKey: 'name', sortDir: 'asc' } as any)
.subscribe((res) => (res.data as Role[]).forEach((r) => this.roleMap.set(r.id, r.name)));
effect(() => {
const params = {
page: this.page(),
perPage: this.perPage(),
search: this.search(),
sortKey: this.sort().key,
sortDir: this.sort().dir as SortDir,
};
untracked(() => this.fetch(params));
});
}
private fetch(params: {
page: number;
perPage: number;
search: string;
sortKey: string;
sortDir: SortDir;
}) {
this.loading.set(true);
this.api.list(params).subscribe({
next: (res) => {
this.rows.set(res.data);
this.total.set(res.meta.total);
this.loading.set(false);
},
error: () => {
this.rows.set([]);
this.total.set(0);
this.loading.set(false);
},
});
}
onSearch(q: string) {
this.search.set(q);
this.page.set(1);
}
openCreate() {
this.modalTitle.set('Nouvel utilisateur');
this.editingItem.set(null);
queueMicrotask(() => this.modalOpen.set(true));
}
openEdit(row: User) {
this.modalTitle.set("Modifier l'utilisateur");
this.editingItem.set(row);
queueMicrotask(() => this.modalOpen.set(true));
}
closeModal() {
this.modalOpen.set(false);
}
submitChildForm() {
this.formComp?.onSubmit();
}
onFormSave(payload: Partial<User>) {
const current = this.editingItem();
const req$ = current?.id
? this.api.update(current.id, payload)
: this.api.create(payload as Omit<User, 'id'>);
req$.subscribe({
next: (user) => {
this.closeModal();
toast.success(
current?.id
? `L'utilisateur « ${user?.nom ?? ''} ${
user?.prenom ?? ''
} » a été mis à jour avec succès`
: `L'utilisateur « ${user?.nom ?? ''} ${user?.prenom ?? ''} » a été créé avec succès`
);
this.fetch({
page: this.page(),
perPage: this.perPage(),
search: this.search(),
sortKey: this.sort().key,
sortDir: this.sort().dir as SortDir,
});
},
error: () => {
toast.error(
current?.id
? "Erreur lors de la mise à jour de l'utilisateur"
: "Erreur lors de la création de l'utilisateur",
{ duration: 5000 }
);
},
});
}
remove(row: User) {
if (!confirm(`Supprimer l\'utilisateur « ${row.nom} ${row.prenom} » ?`)) return;
this.api.delete(row.id).subscribe({
next: (ok) => {
if (ok) {
toast.success(`L'utilisateur « ${row.nom} ${row.prenom} » a été supprimé avec succès`);
this.fetch({
page: this.page(),
perPage: this.perPage(),
search: this.search(),
sortKey: this.sort().key,
sortDir: this.sort().dir as SortDir,
});
} else {
toast.error("Erreur lors de la suppression de l'utilisateur", { duration: 5000 });
}
},
error: () => {
toast.error("Erreur lors de la suppression de l'utilisateur", { duration: 5000 });
},
});
}
}