agent done

This commit is contained in:
OnlyPapy98
2026-01-07 16:06:54 +01:00
parent 0ae7fa316e
commit d7bcbce50d
16 changed files with 658 additions and 425 deletions

View File

@@ -48,7 +48,7 @@ export interface Agent {
autreTelephone?: string;
// TPE assignés (actifs seulement)
tpes?: TpeDevice[] | TpeDevice;
terminauxIds?: number[] | number;
createdAt?: string;
updatedAt?: string;

View File

@@ -66,7 +66,7 @@ interface AgentApiResponse {
statutMarital?: string;
epoux?: string;
autreTelephone?: string;
tpes?: TpeDevice;
terminauxIds?: number[] | number;
createdAt?: string;
updatedAt?: string;
createdBy?: string;
@@ -159,7 +159,7 @@ export class AgentService {
statutMarital: apiAgent.statutMarital,
epoux: apiAgent.epoux,
autreTelephone: apiAgent.autreTelephone,
tpes: apiAgent.tpes ,
terminauxIds: apiAgent.terminauxIds ,
createdAt: apiAgent.createdAt,
updatedAt: apiAgent.updatedAt,
createdBy: apiAgent.createdBy,
@@ -227,6 +227,18 @@ export class AgentService {
return payload;
}
assigner(tpeId: string, agentId:string):Observable<Agent | undefined>{
return this.http.post<Agent>(`${this.apiUrl}/${agentId}/terminaux/${tpeId}`,
{Headers: this.getNgrokHeaders()}).pipe(map(res=> res),
catchError((err)=>{
console.error(err);
return of(undefined);
})
)
}
// GET /api/v1/agents/{id} - Get by ID
getById(id: string): Observable<Agent | undefined> {
if (USE_SERVER) {
@@ -260,7 +272,6 @@ export class AgentService {
})
.pipe(
map((res) => {
console.log(res);
const agents = res.content.map((apiAgent) => {
const transformed = this.transformAgent(apiAgent);
return transformed;

View File

@@ -44,7 +44,6 @@ export class Layout {
mainMenuItems: MenuItem[] = [
{ icon: '🏠', label: 'Tableau de bord', link: '/', exact: true },
{ icon: '🏟️', label: 'Hippodromes', link: '/hippodromes' },
{ icon: '📅', label: 'Reunions', link: '/reunions' },
{ icon: '🏇', label: 'Courses', link: '/courses' },
{ icon: 'icon-chart-bar', label: 'Résultats des courses', link: '/resultat' },
{ icon: '💰', label: 'Gains (cagnotte)', link: '/gains' },

View File

@@ -307,42 +307,19 @@
}
<!-- TPE Assignés -->
@if (getAgentTpes(agent.id).length > 0) {
<z-card class="p-4">
<div class="text-lg font-semibold mb-4">TPE Assignés ({{ getAgentTpes(agent.id).length }})</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-3">
@for (tpe of getAgentTpes(agent.id); track tpe.id) {
<div class="px-3 py-2.5 rounded bg-primary/10 border border-primary/20">
<div class="flex items-start justify-between mb-2">
<div class="font-medium text-sm">{{ tpe.numeroSerie }}</div>
@if (tpe.statut) {
<span class="text-xs px-2 py-0.5 rounded bg-surface text-muted-foreground">
{{ formatTpeStatut(tpe.statut) }}
</span>
@if (tpeArray()) {
@for (tpe of tpeDevices(); track tpe.id) {
<ng-container
*ngTemplateOutlet="tpeCard; context: { $implicit: tpe }"
/>
}
</div>
<div class="space-y-1 text-xs text-muted-foreground">
@if (tpe.modeleAppareil) {
<div>
<span class="font-medium">Modèle:</span> {{ tpe.modeleAppareil }}
</div>
}
@if (tpe.numeroSerie) {
<div>
<span class="font-medium">Série:</span> {{ tpe.numeroSerie }}
</div>
}
@if (tpe.typeTerminal) {
<div>
<span class="font-medium">Type:</span> {{ tpe.typeTerminal }}
</div>
}
</div>
</div>
}
</div>
</z-card>
@else {
<ng-container
*ngTemplateOutlet="tpeCard; context: { $implicit: tpeDevice() }"
/>
}
</div>
}
<div modal-actions class="flex justify-end gap-2">
@@ -357,20 +334,20 @@
}
<!-- TPE Assignment Modal -->
@if (assigningAgent()) {
@if (assigningAgent() !== undefined) {
<app-modal
[open]="assignTpeModalOpen()"
[title]="'Assigner un TPE à ' + (assigningAgent()?.nom || '') + ' ' + (assigningAgent()?.prenom || '')"
(close)="closeAssignTpeModal()"
size="md"
size="xxl"
>
<div class="space-y-4">
@if (tpesLoading()) {
<div class="text-center py-4">Chargement des TPE disponibles...</div>
} @else if (availableTpes().length === 0) {
<div class="text-center py-4 text-muted-foreground">Aucun TPE disponible</div>
} @else {
<z-form-field>
<app-tpe-select (selectionChange)="selectedTpeId.set($event)" [agent]="assigningAgent()" [selected]="getSelectedTpeIds()" ></app-tpe-select>
<!-- <z-form-field>
<label z-form-label>Sélectionner un TPE</label>
<div z-form-control>
<z-select
@@ -388,14 +365,43 @@
}
</z-select>
</div>
</z-form-field>
</z-form-field> -->
}
</div>
<div modal-actions class="flex justify-end gap-2">
<z-button zType="destructive" (click)="closeAssignTpeModal()">Annuler</z-button>
<button z-button [disabled]="!selectedTpeId() || tpesLoading()" (click)="confirmAssignTpe()">
<button z-button [disabled]="selectedTpeId().length === 0 || tpesLoading()" (click)="confirmAssignTpe()">
Assigner
</button>
</div>
</app-modal>
}
<ng-template #tpeCard let-tpe>
<div class="px-3 py-2.5 rounded bg-primary/10 border border-primary/20">
<div class="flex items-start justify-between mb-2">
<div class="font-medium text-sm">
{{ tpe.numeroSerie }}
</div>
@if (tpe.statut) {
<span class="text-xs px-2 py-0.5 rounded bg-surface text-muted-foreground">
{{ formatTpeStatut(tpe.statut) }}
</span>
}
</div>
<div class="space-y-1 text-xs text-muted-foreground">
@if (tpe.modeleAppareil) {
<div><span class="font-medium">Modèle:</span> {{ tpe.modeleAppareil }}</div>
}
@if (tpe.numeroSerie) {
<div><span class="font-medium">Série:</span> {{ tpe.numeroSerie }}</div>
}
@if (tpe.typeTerminal) {
<div><span class="font-medium">Type:</span> {{ tpe.typeTerminal }}</div>
}
</div>
</div>
</ng-template>

View File

@@ -27,6 +27,7 @@ import { forkJoin, of } from 'rxjs';
import { switchMap, catchError } from 'rxjs/operators';
import { toast } from 'ngx-sonner';
import { AgentForm } from '@shared/forms/agent-form/agent-form';
import { TpeSelect } from "../tpe-select/tpe-select";
@Component({
standalone: true,
@@ -41,11 +42,10 @@ import { AgentForm } from '@shared/forms/agent-form/agent-form';
Modal,
ZardButtonComponent,
ZardCardComponent,
ZardSelectComponent,
ZardSelectItemComponent,
ZardFormModule,
AgentForm
],
AgentForm,
TpeSelect
],
})
export class AgentsPage {
rows = signal<Agent[]>([]);
@@ -67,11 +67,17 @@ export class AgentsPage {
// TPE Assignment modal
assignTpeModalOpen = signal(false);
assigningAgent = signal<Agent | null>(null);
assigningAgent = signal<Agent | undefined>(undefined);
availableTpes = signal<TpeDevice[]>([]);
selectedTpeId = signal<string>('');
selectedTpeId = signal<string[]>([]);
tpesLoading = signal(false);
tpeDevice = signal<TpeDevice | undefined>(undefined);
tpeDevices = signal<TpeDevice[]>([]);
tpeArray = signal<boolean>(false);
@ViewChild(AgentFullForm) formComp?: AgentFullForm;
formatTpeStatut(statut: TpeStatus): string {
@@ -95,28 +101,19 @@ export class AgentsPage {
{ key: 'profil', label: 'Profil', sortable: true, defaultVisible: true },
{ key: 'statut', label: 'Statut', sortable: true, defaultVisible: true, cell: (a) => this.renderStatutBadge(a.statut) },
{ key: 'phone', label: 'Téléphone', sortable: true, defaultVisible: true },
{ key: 'zone', label: 'Zone', sortable: true },
{ key: 'kiosk', label: 'Kiosque', sortable: true },
{ key: 'tpes', label: 'TPE', cell: (a) => `${(this.getAgentTpes(a.id) || []).length}` },
{ key: 'limites', label: 'Limites', cell: (a) => this.formatLimits(a) },
{ key: 'dateEmbauche', label: 'Embauché le', cell: (a) => (a.dateEmbauche ? new Date(a.dateEmbauche).toLocaleDateString() : '') },
{ key: 'zone', label: 'Zone', sortable: true, defaultVisible: true },
];
tpeMap = new Map<string, TpeDevice>();
agentTpesMap = new Map<string, TpeDevice[]>();
constructor(
private api: AgentService,
private tpeSvc: TpeService,
private familyMemberService: AgentFamilyMemberService
) {
// Preload TPE maps for display
this.tpeSvc
.list({ page: 1, size: 200, search: '', sortKey: 'id', sortDir: 'asc' } as any)
.subscribe((res) => {
const tpes = res.content as TpeDevice[];
this.rebuildTpeMaps(tpes);
});
effect(() => {
const params = {
page: this.page(),
@@ -139,12 +136,9 @@ export class AgentsPage {
this.loading.set(true);
this.api.list(params).subscribe({
next: (res) => {
console.log(res.content);
this.rows.set(res.content);
this.total.set(res.pageable.total);
this.loading.set(false);
// Refresh TPE map to ensure we have latest data
this.refreshTpeMap();
},
error: () => {
this.rows.set([]);
@@ -154,32 +148,6 @@ export class AgentsPage {
});
}
private refreshTpeMap() {
this.tpeSvc
.list({ page: 1, size: 200, search: '', sortKey: 'imei', sortDir: 'asc' } as any)
.subscribe((res) => {
const tpes = res.content as TpeDevice[];
this.rebuildTpeMaps(tpes);
});
}
private rebuildTpeMaps(tpes: TpeDevice[]) {
this.tpeMap.clear();
this.agentTpesMap.clear();
tpes.forEach((t) => {
this.tpeMap.set(t.id, t);
const agentId = t.agentConnecteId;
if (agentId) {
const list = this.agentTpesMap.get(agentId) || [];
list.push(t);
this.agentTpesMap.set(agentId, list);
}
});
}
getAgentTpes(agentId: string): TpeDevice[] {
return this.agentTpesMap.get(agentId) || [];
}
renderStatutBadge(statut: Agent['statut'] | string | undefined): string {
if (!statut) return '';
@@ -218,6 +186,8 @@ export class AgentsPage {
closeModal() {
this.modalOpen.set(false);
}
openDetail(row: Agent) {
// Fetch full agent details
this.api.getById(row.id).subscribe({
@@ -233,6 +203,31 @@ export class AgentsPage {
this.detailFamilyMembers.set([]);
},
});
const tpeIds = agent.terminauxIds;
if(Array.isArray(tpeIds)){
this.tpeArray.set(true);
forkJoin(
tpeIds.map(id=>this.tpeSvc.getById(String(id)))
).subscribe({
next:(tpes)=>{
this.tpeDevices.set(tpes.filter(tpe=>tpe!==undefined))
},
error:(err)=>{
console.error(err);
}
})
}else{
this.tpeArray.set(false);
this.tpeSvc.getById(String(tpeIds)).subscribe({
next:(tpe)=>{
if(tpe && tpe !== undefined)
this.tpeDevice.set(tpe);
},
error:(err)=>{
console.error(err);
}
})
}
this.detailModalOpen.set(true);
}
},
@@ -386,6 +381,23 @@ export class AgentsPage {
});
}
getSelectedTpeIds = (): string[] => {
const ids = this.assigningAgent()?.terminauxIds;
if (!ids) return []; // undefined ou null → tableau vide
// Si c'est un tableau, on map en string
if (Array.isArray(ids)) {
return ids.map(id => id.toString());
}
// Si c'est un seul nombre, on retourne un tableau avec un élément
return [ids.toString()];
};
remove(row: Agent) {
if (!confirm(`Supprimer l\'agent ${row.code} ?`)) return;
this.api.delete(row.id).subscribe(() =>
@@ -401,75 +413,91 @@ export class AgentsPage {
openAssignTpe(agent: Agent) {
this.assigningAgent.set(agent);
this.selectedTpeId.set('');
this.loadAvailableTpes();
this.selectedTpeId.set([]);
this.assignTpeModalOpen.set(true);
}
loadAvailableTpes() {
this.tpesLoading.set(true);
const agent = this.assigningAgent();
if (!agent) {
this.availableTpes.set([]);
this.tpesLoading.set(false);
return;
}
// loadAvailableTpes() {
// this.tpesLoading.set(true);
// const agent = this.assigningAgent();
// if (!agent) {
// this.availableTpes.set([]);
// this.tpesLoading.set(false);
// return;
// }
const currentAgentTpes = this.agentTpesMap.get(agent.id) || [];
const agentTpeIds = new Set(currentAgentTpes.map((t) => t.id));
// const currentAgentTpes = this.agentTpesMap.get(agent.id) || [];
// const agentTpeIds = new Set(currentAgentTpes.map((t) => t.id));
// Load available TPEs (DISPONIBLE or VALIDE status)
forkJoin([this.tpeSvc.getByStatut('ACTIF'), this.tpeSvc.getByStatut('ACTIF')]).subscribe({
next: ([disponibleTpes, valideTpes]) => {
// Combine and filter: only show TPEs that are not assigned to any agent AND not already assigned to this agent
const allTpes = [...disponibleTpes, ...valideTpes];
const available = allTpes.filter(
(t) =>
!t.agentConnecteId &&
(t.statut === 'ACTIF') &&
!agentTpeIds.has(t.id)
);
// Remove duplicates
const uniqueTpes = Array.from(new Map(available.map((t) => [t.id, t])).values());
this.availableTpes.set(uniqueTpes);
this.tpesLoading.set(false);
},
error: () => {
this.availableTpes.set([]);
this.tpesLoading.set(false);
},
});
}
// // Load available TPEs (DISPONIBLE or VALIDE status)
// forkJoin([this.tpeSvc.getByStatut('ACTIF'), this.tpeSvc.getByStatut('ACTIF')]).subscribe({
// next: ([disponibleTpes, valideTpes]) => {
// // Combine and filter: only show TPEs that are not assigned to any agent AND not already assigned to this agent
// const allTpes = [...disponibleTpes, ...valideTpes];
// const available = allTpes.filter(
// (t) =>
// !t.agentConnecteId &&
// (t.statut === 'ACTIF') &&
// !agentTpeIds.has(t.id)
// );
// // Remove duplicates
// const uniqueTpes = Array.from(new Map(available.map((t) => [t.id, t])).values());
// this.availableTpes.set(uniqueTpes);
// this.tpesLoading.set(false);
// },
// error: () => {
// this.availableTpes.set([]);
// this.tpesLoading.set(false);
// },
// });
// }
// testAssigne(tpeIds: string[]){
// console.log(tpeIds);
// }
confirmAssignTpe() {
const agent = this.assigningAgent();
const tpeId = this.selectedTpeId();
if (!agent || !tpeId) {
if (!agent || tpeId.length === 0) {
alert('Veuillez sélectionner un TPE');
return;
}
// Assign TPE to agent
this.tpeSvc.assigner(tpeId, agent.id).subscribe({
next: (tpe) => {
if (tpe) {
// Fermer le modal et recharger complètement la page
forkJoin(this.selectedTpeId().map(id=> this.api.assigner(id, agent.id))).subscribe(
{
next:()=>{
this.assignTpeModalOpen.set(false);
this.assigningAgent.set(null);
this.selectedTpeId.set('');
// Rechargement complet pour s'assurer que la liste des agents / TPE est à jour
window.location.reload();
this.assigningAgent.set(undefined);
this.selectedTpeId.set([]);
toast.success(`Tpe affecté à l'agent avec succès1`)
},
error: (err)=>{
console.error(err);
}
},
error: () => {
alert("Erreur lors de l'assignation du TPE");
},
});
}
)
// // Assign TPE to agent
// this.tpeSvc.assigner(tpeId, agent.id).subscribe({
// next: (tpe) => {
// if (tpe) {
// // Fermer le modal et recharger complètement la page
// this.selectedTpeId.set('');
// // Rechargement complet pour s'assurer que la liste des agents / TPE est à jour
// window.location.reload();
// }
// },
// error: () => {
// alert("Erreur lors de l'assignation du TPE");
// },
// });
}
closeAssignTpeModal() {
this.assignTpeModalOpen.set(false);
this.assigningAgent.set(null);
this.selectedTpeId.set('');
this.assigningAgent.set(undefined);
this.selectedTpeId.set([]);
}
}

View File

@@ -0,0 +1,35 @@
<div class="p-4 border rounded-lg shadow bg-white dark:bg-gray-900">
@if (loading()) {
<div class="flex justify-center py-4">
<div class="w-6 h-6 border-2 border-gray-300 border-t-blue-600 rounded-full animate-spin"></div>
</div>
}
@if(!loading()){
@if(tpes().length > 0){
<div>
<app-data-table
[data]="tpes()"
[columns]="columns">
<ng-template #rowActions let-row>
<div class="flex gap-2 flex-wrap">
<input type="checkbox" (click)="toggleTpe(row)" [checked] = "isChecked(row)" />
</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>
}
@if (tpes().length === 0) {
<p class="text-gray-500 dark:text-gray-400">
Aucun TPE disponible.
</p>
}
}
</div>

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { TpeSelect } from './tpe-select';
describe('TpeSelect', () => {
let component: TpeSelect;
let fixture: ComponentFixture<TpeSelect>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [TpeSelect]
})
.compileComponents();
fixture = TestBed.createComponent(TpeSelect);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,110 @@
import { Component, effect, EventEmitter, Input, Output, signal } from '@angular/core';
import { SortState, TableColumn, DataTable } from '@shared/components/data-table/data-table';
import { ListParams, SortDir } from '@shared/paging/paging';
import { Agent } from 'src/app/core/interfaces/agent';
import { TpeDevice } from 'src/app/core/interfaces/tpe';
import { TpeService } from 'src/app/core/services/tpe';
import { Paginator } from "@shared/components/paginator/paginator";
@Component({
selector: 'app-tpe-select',
imports: [DataTable, Paginator],
templateUrl: './tpe-select.html',
styleUrl: './tpe-select.css',
})
export class TpeSelect {
@Input() agent?: Agent; // Agent pour filtrer les TPE assignés
@Input() selected: string[] = []; // Ids de TPE à cocher par défaut
@Output() selectionChange = new EventEmitter<string[]>(); // TPE sélectionnés
tpes = signal<TpeDevice[]>([]);
total = signal(0);
loading = signal<boolean>(true);
selectedIds = signal<Set<string>>(new Set());
page = signal(0);
perPage = signal(10);
search = signal('');
sort = signal<SortState>({ key: 'id', dir: 'asc' });
columns:TableColumn<TpeDevice>[] = [
{
key: 'numeroSerie',
label: "Numero de serie"
},
{
key: 'versionLogicielle',
label: "Version du logiciel"
},
{
key: 'modeleAppareil',
label: "Model"
},
{
key: 'systemeExploitation',
label: 'Système d\'exploitation'
},
{
key: 'versionOs',
label: 'Version Os'
}
]
constructor(private tpeService: TpeService) {
effect(()=>{
const params = {
page: this.page(),
size: this.perPage(),
sortKey: this.sort().key,
sortDir: this.sort().dir as SortDir,
}
this.loadTpes(params);
})
}
ngOnInit() {
// Initialiser les TPE sélectionnés si fournis
this.selectedIds.set(new Set(this.selected));
}
private loadTpes(params:ListParams) {
this.loading.set(true);
this.tpeService.list(params).subscribe({
next: (res) => {
// Filtrer : TPE non assignés ou déjà assignés à cet agent
// console.log(res.content);
// const available = res.content.filter(
// (t) =>
// !t.agentConnecteId || t.agentConnecteId === this.agent?.id
// );
this.tpes.set(res.content);
this.total.set(res.pageable.total);
this.loading.set(false);
},
error: (err) => {
console.error(err);
this.loading.set(false);
},
});
}
toggleTpe(tpe: TpeDevice) {
const current = new Set(this.selectedIds());
if (current.has(tpe.id)) {
current.delete(tpe.id);
} else {
current.add(tpe.id);
}
this.selectedIds.set(current);
this.selectionChange.emit(Array.from(current));
}
isChecked(tpe: TpeDevice) {
return this.selectedIds().has(String(tpe.id));
}
}

View File

@@ -27,6 +27,7 @@ import { ZardFormModule } from '@shared/components/form/form.module';
import { forkJoin, Subject } from 'rxjs';
import { debounceTime, distinctUntilChanged, switchMap } from 'rxjs/operators';
import { toast } from 'ngx-sonner';
import { PointsVenteService } from 'src/app/core/services/points-vente';
@Component({
standalone: true,
@@ -53,10 +54,10 @@ export class TpePage implements OnInit {
total = signal(0);
loading = signal(false);
page = signal(1);
page = signal(0);
perPage = signal(10);
search = signal('');
sort = signal<SortState>({ key: 'imei', dir: 'asc' });
sort = signal<SortState>({ key: 'id', dir: 'asc' });
selectedStatut = signal<TpeStatus | null>(null);
modalOpen = signal(false);
@@ -96,11 +97,31 @@ export class TpePage implements OnInit {
}
cols: TableColumn<TpeDevice>[] = [
{ key: 'imei', label: 'IMEI', sortable: true },
{ key: 'serial', label: 'N° de Série', sortable: true },
{ key: 'type', label: 'Type', sortable: true },
{ key: 'marque', label: 'Marque', sortable: true },
{ key: 'modele', label: 'Modèle', sortable: true },
{ key: 'numeroSerie', label: 'Numéro de série', sortable: true },
{
key: 'pointDeVenteId',
label: 'Point de vente',
sortable: true,
cell:(p) => {
let pointVente = signal('');
this.pointVenteService.getById(p.pointDeVenteId).subscribe({
next: (pdv)=>{
if(!pdv || pdv === undefined){
pointVente.set("Aucun point")
return;
};
pointVente.set(`${pdv.ville}/${pdv.adresse}`)
},
error:(err)=>{
pointVente.set('Aucun point')
}
})
return pointVente();
},
},
{ key: 'versionLogicielle', label: 'Version', sortable: true },
{ key: 'typeTerminal', label: 'Type', sortable: true },
{ key: 'systemeExploitation', label: 'Sytème', sortable: true },
{ key: 'statut', label: 'Statut', sortable: true, cell: (d) => this.formatStatut(d.statut) },
{
key: 'assigne',
@@ -136,12 +157,13 @@ export class TpePage implements OnInit {
},
];
allStatuses: TpeStatus[] = [
'ACTIF',
'HORS_SERVICE'
];
allStatuses: TpeStatus[] = ['ACTIF', 'HORS_SERVICE'];
constructor(private api: TpeService, private agentService: AgentService) {
constructor(
private api: TpeService,
private agentService: AgentService,
private pointVenteService: PointsVenteService
) {
effect(() => {
// Only trigger fetch when page, perPage, or sort changes (not search - handled by searchSubject)
const searchValue = this.search();
@@ -321,7 +343,8 @@ export class TpePage implements OnInit {
}
onUpdateStatut(row: TpeDevice, newStatut: TpeStatus) {
if (!confirm(`Changer le statut de ${row.numeroSerie} vers ${this.formatStatut(newStatut)} ?`)) return;
if (!confirm(`Changer le statut de ${row.numeroSerie} vers ${this.formatStatut(newStatut)} ?`))
return;
this.api.updateStatut(row.id, newStatut).subscribe({
next: () => {
this.fetch({
@@ -435,7 +458,7 @@ export class TpePage implements OnInit {
: this.api.create(payload as Omit<TpeDevice, 'id'>);
req$.subscribe({
next: (result) => {
toast.success('Tpe créé avec succès!')
toast.success('Tpe créé avec succès!');
// For update, check if result is valid (update can return undefined on error)
if (current?.id && !result) {
console.error('Update failed - result is undefined');

View File

@@ -16,7 +16,7 @@ import { ZardCheckboxComponent } from "@shared/components/checkbox/checkbox.comp
standalone: true,
templateUrl: './agent-form.html',
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [CommonModule, ReactiveFormsModule, ZardFormModule, ZardInputDirective, ZardSelectComponent, ZardSelectItemComponent, ZardButtonComponent],
imports: [CommonModule, ReactiveFormsModule, ZardFormModule, ZardInputDirective, ZardSelectComponent, ZardSelectItemComponent],
})
export class AgentForm {
@Output() save = new EventEmitter<Agent>();
@@ -121,6 +121,7 @@ export class AgentForm {
this.submitted = false;
return;
}
console.log(v);
this.form.reset({
code: v.code || '',
profil: v.profil || '',

View File

@@ -70,7 +70,7 @@
<z-form-field>
<label z-form-label>Point de vente</label>
<input [value]="pointDeVenteText()" (click)="onClose()" (input)="pointDeVenteTextChange($event)" z-input placeholder="Entrez le nom du point de vente"/>
<input [value]="pointDeVenteText()" (blur)="onClose()" (input)="pointDeVenteTextChange($event)" z-input placeholder="Entrez le nom du point de vente"/>
<div z-form-control [errorMessage]="errorMessage('pointDeVenteId') || ''">
@if (pointDeVenteLoading()){
<div class="flex items-center justify-center">
@@ -85,8 +85,7 @@
@for (pdv of pointsDevente; track pdv.id) {
<li
class="px-3 py-2 cursor-pointer hover:bg-blue-500"
(click)="selectPointDeVente(pdv)"
>
(mousedown)="selectPointDeVente(pdv)">
{{ pdv.nom }} / {{ pdv.code }}
</li>
}

View File

@@ -51,6 +51,7 @@ export class TpeForm {
pointsDevente:PointVente[] = [];
statuts = [
{
label: 'Actif',
@@ -81,16 +82,6 @@ export class TpeForm {
agentConnecteId: ['1'],
journalSession: ['1'],
});
effect(()=>{
const text = this.pointDeVenteText();
const params: ListParams = {
page: 0,
size: 10,
search: text
}
this.getPointDeventeFromText(text, params);
})
}
@@ -99,6 +90,13 @@ export class TpeForm {
pointDeVenteTextChange =(event: Event)=>{
const value = (event.target as HTMLInputElement).value;
this.pointDeVenteText.set(value);
const text = this.pointDeVenteText();
const params: ListParams = {
page: 0,
size: 10,
search: text
}
this.getPointDeventeFromText(text, params);
}
getPointDeventeFromText=(text: string, params: ListParams)=>{

View File

@@ -1,5 +1,5 @@
export const environment = {
production: false,
apiBaseUrl: 'http://192.168.40.225:8080',
apiBaseUrl: 'http://192.168.40.204:8080',
depouillementBaseUrl: 'http://192.168.1.235:8383'
};