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>
This commit is contained in:
2026-07-03 11:26:48 -06:00
parent 9098b126ad
commit 48979dca6f
38 changed files with 1534 additions and 617 deletions

View File

@@ -1,5 +1,5 @@
import { Component, ChangeDetectorRef } from '@angular/core';
import { ModalController, MenuController, NavController } from '@ionic/angular';
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';
@@ -7,6 +7,7 @@ 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',
@@ -23,6 +24,7 @@ export class PendingPage {
constructor(
private modalController: ModalController,
private alertController: AlertController,
private menu: MenuController,
private navCtrl: NavController,
private events: EventService,
@@ -83,4 +85,45 @@ export class PendingPage {
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();
}
}
}