Files
Jobhero_front/src/app/pages/contracts/pending/pending.page.ts
Carlos 48979dca6f feat: Branch betos — propiedades, rediseño postulaciones, chat contratos y flujo cancelar/repostular
- Sistema de propiedades: modal add-property con autocomplete y selector de ícono
- category.page rediseñado: selector de propiedad, fotos (Capacitor Camera), sin fecha/precio
- Modal postulate-offer: proveedor propone 2 fechas requeridas + monto con validación de cuota mínima
- viewsuppliers: chips de ordenamiento frontend (fecha, precio, certificados)
- hire.page: selección de fecha (date_1/date_2) antes de contratar; selected_date en contracts/create y contracts/coupon
- Modal contract-discussion: chat de burbujas para contratos activos
- contracted.page: botón de chat por contrato
- pending.page: botones cancelar y repostular por postulación
- Modal repostulate: pre-llena categoría/propiedad, archiva original como perdido y crea nueva con related_postulation_id
- current.page: temporizador de expiración basado en time_created (1000 min), oculta expiradas
- ichamba.service: nuevos métodos properties, cancelPostulation, contractDiscussion, updated signatures

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-03 11:26:48 -06:00

130 lines
4.5 KiB
TypeScript
Executable File

import { Component, ChangeDetectorRef } from '@angular/core';
import { AlertController, ModalController, MenuController, NavController } from '@ionic/angular';
import { EventService } from '../../../services/event.service';
import { EnvService } from 'src/app/services/env.service';
import { AuthService } from 'src/app/services/auth.service';
import { IchambaService } from 'src/app/services/ichamba.service';
import { TranslateService } from '@ngx-translate/core';
import { LanguageService } from 'src/app/services/language.service';
import { AlertService } from 'src/app/services/alert.service';
import { RepostulateePage } from '../../postulations/repostulate/repostulate.page';
@Component({
selector: 'app-pending',
templateUrl: './pending.page.html',
styleUrls: ['./pending.page.scss'],
standalone: false
})
export class PendingPage {
pcontracts: any[] = [];
pcontracts_dates: any[] = [];
lang: boolean = false;
loading = true;
constructor(
private modalController: ModalController,
private alertController: AlertController,
private menu: MenuController,
private navCtrl: NavController,
private events: EventService,
private authService: AuthService,
private alertService: AlertService,
private ichambaService: IchambaService,
private translateService: TranslateService,
private languageService: LanguageService,
private env: EnvService,
private cdr: ChangeDetectorRef,
) {
this.events.subscribe('refreshpcontracts', (data) => {
this.getpcontracts();
});
}
ionViewWillEnter() {
this.lang = this.languageService.getDefaultLanguage() === 'es';
this.loading = true;
this.getpcontracts();
}
refresh(event: any) {
this.ichambaService.getPendingcontracts().subscribe(
data => {
this.pcontracts = data;
this.pcontracts_dates = [];
for (var i of this.pcontracts) {
const locale = this.lang ? 'es-US' : 'en-US';
this.pcontracts_dates.push(new Date((new Date(i.date).toLocaleString('en-US') + ' UTC').replace(',', '')).toLocaleDateString(locale, { weekday: 'long', year: 'numeric', month: 'short', day: 'numeric', hour: 'numeric', minute: 'numeric', timeZoneName: 'long' }));
}
this.cdr.detectChanges();
event.target.complete();
}, error => {
this.alertService.presentToast(this.translateService.instant('alerts.error') + error['status']);
event.target.complete();
});
}
getpcontracts() {
this.ichambaService.getPendingcontracts().subscribe(
data => {
this.pcontracts = data;
this.pcontracts_dates = [];
for (var i of this.pcontracts) {
const locale = this.lang ? 'es-US' : 'en-US';
this.pcontracts_dates.push(new Date((new Date(i.date).toLocaleString('en-US') + ' UTC').replace(',', '')).toLocaleDateString(locale, { weekday: 'long', year: 'numeric', month: 'short', day: 'numeric', hour: 'numeric', minute: 'numeric', timeZoneName: 'long' }));
}
this.loading = false;
this.cdr.detectChanges();
}, error => {
this.loading = false;
this.alertService.presentToast(this.translateService.instant('alerts.error') + error['status']);
});
}
viewsuppliers(postulation_id: String) {
this.navCtrl.navigateForward(['/viewsuppliers/', postulation_id]);
}
async confirmCancel(postulation: any) {
const alert = await this.alertController.create({
header: 'Cancelar postulación',
message: ' ',
buttons: [
{ text: 'No', role: 'cancel' },
{
text: 'Sí, cancelar',
role: 'destructive',
handler: () => this.doCancel(postulation.id)
}
]
});
await alert.present();
alert.querySelector('.alert-message')!.innerHTML = '¿Estás seguro de que deseas cancelar esta postulación de <strong>' + postulation.category + '</strong>?';
}
private doCancel(id: any) {
this.ichambaService.cancelPostulation(id).subscribe({
next: () => {
this.alertService.presentToast('Postulación cancelada.');
this.getpcontracts();
},
error: (error: any) => {
this.alertService.presentToast('Error al cancelar: ' + error['status']);
}
});
}
async openRepostulate(postulation: any) {
const modal = await this.modalController.create({
component: RepostulateePage,
componentProps: { postulation },
});
await modal.present();
const { data } = await modal.onDidDismiss();
if (data?.reposted) {
this.getpcontracts();
}
}
}