import { Component, ChangeDetectorRef, OnDestroy } from '@angular/core'; import { CommonModule } from '@angular/common'; import { FormsModule } from '@angular/forms'; import { TableModule } from 'primeng/table'; import { RouteNoAssignedResponse } from '../../../core/models/route.model'; import { RouteState, UnassignedAssignment } from '../../../core/route-state/route'; import { Subscription } from 'rxjs'; import { OrsService } from '../../../core/services/ors.service'; @Component({ standalone: true, selector: 'app-no-assigned-route', imports: [CommonModule, FormsModule, TableModule], templateUrl: './no-assigned-route.component.html', styleUrls: ['./no-assigned-route.component.css'] }) export class NoAssignedRouteComponent implements OnDestroy { noAssignedRoutes: RouteNoAssignedResponse[] = []; isLoading = false; cols: { field: string; header: string }[] = []; private subs: Subscription[] = []; assignmentUser: Record = {}; assignmentDays: Record = {}; assigningId: number | null = null; actionError: string | null = null; constructor( private routesState: RouteState, private cdr: ChangeDetectorRef, private orsService: OrsService ) {} ngOnInit() { this.subs.push( this.routesState.loading$.subscribe(value => { this.isLoading = value; this.cdr.detectChanges(); }) ); this.subs.push( this.routesState.noAssignedRoutes$.subscribe(data => { this.noAssignedRoutes = [...data]; this.cdr.detectChanges(); }) ); this.cols = [ { field: 'pdv_id', header: 'PDV ID' }, { field: 'pdv_nombre', header: 'Nombre' }, { field: 'minimo_horas_semana', header: 'Min. Horas/Sem' }, { field: 'latitud', header: 'Latitud' }, { field: 'longitud', header: 'Longitud' }, { field: 'motivo', header: 'Motivo' } ]; } get userOptions(): { id: string; name: string }[] { return this.routesState.getUsuariosUnicos().map(user => ({ id: user.id, name: user.nombre })); } get dayOptions(): string[] { return this.routesState.getDiasUnicos(); } toggleDay(pdvId: number, day: string, checked: boolean): void { const key = String(pdvId); const days = new Set(this.assignmentDays[key] ?? []); checked ? days.add(day) : days.delete(day); this.assignmentDays[key] = Array.from(days); } async assignRoute(route: RouteNoAssignedResponse): Promise { const userId = this.assignmentUser[String(route.pdv_id)]; const days = this.assignmentDays[String(route.pdv_id)] ?? []; if (!userId || !days.length) { this.actionError = 'Selecciona usuario y al menos un día antes de asignar.'; return; } const user = this.routesState.getAssignedSnapshot().find(item => String(item.json.usuario_id) === userId); if (!user) return; this.assigningId = route.pdv_id; this.actionError = null; try { const origin = [Number(user.json.longitud_usuario), Number(user.json.latitud_usuario)]; const destination = [Number(route.longitud), Number(route.latitud)]; const assignments: UnassignedAssignment[] = []; for (const day of days) { const result = await this.orsService.processPairs([{ pdv_id: route.pdv_id, origin, destination }], 1, true); const geo = (result[0] as { geojson?: { features?: { properties?: { summary?: { distance: number; duration: number } } }[] } }).geojson; const summary = geo?.features?.[0]?.properties?.summary; if (!summary) throw new Error('ORS no devolvió una ruta vial'); const capacity = this.routesState.canAssignToDay(userId, day, route.minimo_horas_semana, undefined, summary.duration / 3600); if (!capacity.allowed) { this.actionError = `${day}: excede la capacidad diaria (${capacity.totalHours.toFixed(1)} h de ${capacity.capacityHours.toFixed(1)} h).`; return; } assignments.push({ userId, day, distance: summary.distance / 1000, duration: summary.duration / 3600 }); } this.routesState.addAssignedFromUnassignedMany(route, assignments); delete this.assignmentUser[String(route.pdv_id)]; delete this.assignmentDays[String(route.pdv_id)]; } catch { this.actionError = `No se pudo calcular la ruta vial para ${route.pdv_nombre}.`; } finally { this.assigningId = null; this.cdr.detectChanges(); } } ngOnDestroy() { this.subs.forEach(s => s.unsubscribe()); } }