- 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>
130 lines
4.5 KiB
TypeScript
Executable File
130 lines
4.5 KiB
TypeScript
Executable File
import { Component, ChangeDetectorRef } from '@angular/core';
|
|
import { MenuController, NavController, ModalController } 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 { AlertService } from 'src/app/services/alert.service';
|
|
import { Browser } from '@capacitor/browser';
|
|
import { PostulateOfferPage } from '../postulate-offer/postulate-offer.page';
|
|
|
|
@Component({
|
|
selector: 'app-current',
|
|
templateUrl: './current.page.html',
|
|
styleUrls: ['./current.page.scss'],
|
|
standalone: false
|
|
})
|
|
export class CurrentPage {
|
|
|
|
postulations: any[] = [];
|
|
postulations_dates: any[] = [];
|
|
loading = true;
|
|
minFee: number = 0;
|
|
private timerInterval: any;
|
|
|
|
constructor(
|
|
private menu: MenuController,
|
|
private navCtrl: NavController,
|
|
private events: EventService,
|
|
private authService: AuthService,
|
|
private alertService: AlertService,
|
|
private ichambaService: IchambaService,
|
|
private modalCtrl: ModalController,
|
|
private env: EnvService,
|
|
private cdr: ChangeDetectorRef,
|
|
) {
|
|
this.events.subscribe('refreshpostulations', (data) => {
|
|
this.getpostulations();
|
|
});
|
|
}
|
|
|
|
ionViewWillEnter() {
|
|
this.loading = true;
|
|
this.getpostulations();
|
|
this.ichambaService.getParameters().subscribe((data: any) => {
|
|
this.minFee = data['min_fee'] ?? 0;
|
|
});
|
|
this.timerInterval = setInterval(() => {
|
|
this.postulations.forEach(p => this.computeTimer(p));
|
|
this.cdr.detectChanges();
|
|
}, 60000);
|
|
}
|
|
|
|
ionViewWillLeave() {
|
|
clearInterval(this.timerInterval);
|
|
}
|
|
|
|
private computeTimer(p: any) {
|
|
const remaining = Math.max(0, Math.floor(
|
|
(new Date(p.time_created).getTime() + 1000 * 60 * 1000 - Date.now()) / 60000
|
|
));
|
|
if (remaining <= 0) {
|
|
p._timer = 'Expirada';
|
|
} else if (remaining < 60) {
|
|
p._timer = `${remaining}m restantes`;
|
|
} else {
|
|
const h = Math.floor(remaining / 60);
|
|
const m = remaining % 60;
|
|
p._timer = `${h}h${m > 0 ? ' ' + m + 'm' : ''} restantes`;
|
|
}
|
|
p._timerCritical = remaining < 60;
|
|
}
|
|
|
|
refresh(event: any) {
|
|
this.ichambaService.getPostulation().subscribe(
|
|
data => {
|
|
this.postulations = data;
|
|
this.postulations_dates = [];
|
|
for (var i of this.postulations) {
|
|
this.postulations_dates.push(new Date((new Date(i.date).toLocaleString('en-US') + ' UTC').replace(',', '')).toLocaleDateString('es-US', { weekday: 'long', year: 'numeric', month: 'short', day: 'numeric', hour: 'numeric', minute: 'numeric', timeZoneName: 'long' }));
|
|
this.computeTimer(i);
|
|
}
|
|
this.cdr.detectChanges();
|
|
event.target.complete();
|
|
}, error => {
|
|
this.alertService.presentToast("Por favor contacte a soporte técnico, Estatus:" + error['status']);
|
|
event.target.complete();
|
|
});
|
|
}
|
|
|
|
getpostulations() {
|
|
this.ichambaService.getPostulation().subscribe(
|
|
data => {
|
|
this.postulations = data;
|
|
this.postulations_dates = [];
|
|
for (var i of this.postulations) {
|
|
this.postulations_dates.push(new Date((new Date(i.date).toLocaleString('en-US') + ' UTC').replace(',', '')).toLocaleDateString('es-US', { weekday: 'long', year: 'numeric', month: 'short', day: 'numeric', hour: 'numeric', minute: 'numeric', timeZoneName: 'long' }));
|
|
this.computeTimer(i);
|
|
}
|
|
this.loading = false;
|
|
this.cdr.detectChanges();
|
|
}, error => {
|
|
this.loading = false;
|
|
this.alertService.presentToast("Por favor contacte a soporte técnico, Estatus:" + error['status']);
|
|
});
|
|
}
|
|
|
|
async addpostulation(id: string) {
|
|
const modal = await this.modalCtrl.create({
|
|
component: PostulateOfferPage,
|
|
componentProps: { postulationId: id, minFee: this.minFee }
|
|
});
|
|
await modal.present();
|
|
const { data } = await modal.onDidDismiss();
|
|
if (!data) return;
|
|
this.ichambaService.setPostulation(id, data.date1, data.date2, data.amount).subscribe({
|
|
next: (res: any) => {
|
|
this.getpostulations();
|
|
this.alertService.presentToast(res['message']);
|
|
},
|
|
error: (error: any) => {
|
|
this.alertService.presentToast("Por favor contacte a soporte técnico, Estatus:" + error['status']);
|
|
}
|
|
});
|
|
}
|
|
|
|
async openMaps(lat: Number, lng: Number) {
|
|
await Browser.open({ url: 'http://maps.google.com/maps?q=' + lat + ',' + lng });
|
|
}
|
|
}
|