Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9f2a0d62e0 | ||
|
|
22e4585bb9 | ||
| 4afaf69d10 | |||
| 68673baf99 |
@@ -16,8 +16,17 @@ android {
|
||||
ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~'
|
||||
}
|
||||
}
|
||||
signingConfigs {
|
||||
release {
|
||||
storeFile file('../../jobhero-release.keystore')
|
||||
storePassword 'JobHero2024!'
|
||||
keyAlias 'jobhero'
|
||||
keyPassword 'JobHero2024!'
|
||||
}
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
signingConfig signingConfigs.release
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
|
||||
@@ -2,15 +2,12 @@ import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { IonicModule } from '@ionic/angular';
|
||||
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [AccordionComponent],
|
||||
declarations: [],
|
||||
imports: [
|
||||
CommonModule,
|
||||
IonicModule
|
||||
],
|
||||
exports: [
|
||||
]
|
||||
exports: []
|
||||
})
|
||||
export class SharedComponentsModule { }
|
||||
|
||||
@@ -25,16 +25,16 @@
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label position="fixed">{{'categories.address' | translate}}</ion-label>
|
||||
<ion-input [(ngModel)]="addressAutocomplete" (ionChange)="autocomplete($event)" value="{{ myAddress }}" (ionFocus)="showlist()"></ion-input>
|
||||
<ion-input [(ngModel)]="addressAutocomplete" (ionInput)="autocomplete($event)" (ionFocus)="showlist()"></ion-input>
|
||||
</ion-item>
|
||||
<ion-list *ngIf="showif">
|
||||
<ion-item button=true (click)="geoloc(places.place_id, places.description, places.terms[1].value)" *ngFor="let places of placesSearch" class="place">
|
||||
<ion-list *ngIf="showif && placesSearch && placesSearch.length > 0">
|
||||
<ion-item button=true (click)="geoloc(places.place_id, places.description)" *ngFor="let places of placesSearch" class="place">
|
||||
{{ places.description }}
|
||||
</ion-item>
|
||||
</ion-list>
|
||||
<ion-item hidden>
|
||||
<ion-item>
|
||||
<ion-label position="fixed">{{'categories.int_number' | translate}}</ion-label>
|
||||
<ion-input value="{{ myIntnumber }}" disabled></ion-input>
|
||||
<ion-input [(ngModel)]="myIntnumber" placeholder="Opcional"></ion-input>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label position="fixed">{{'categories.references' | translate}}</ion-label>
|
||||
|
||||
@@ -102,6 +102,7 @@ export class CategoryPage implements OnInit {
|
||||
const address = results[0].formatted_address;
|
||||
console.log("data_: ", address);
|
||||
this.myAddress = address;
|
||||
this.addressAutocomplete = address; // Sincronizar con el input
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -142,9 +143,9 @@ export class CategoryPage implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
geoloc(place_id: string, place_description: string, place_intnumber: string) {
|
||||
geoloc(place_id: string, place_description: string) {
|
||||
this.myAddress = place_description;
|
||||
this.myIntnumber = place_intnumber;
|
||||
this.addressAutocomplete = place_description; // Sincronizar con el input
|
||||
console.log(place_id);
|
||||
this.hidelist();
|
||||
new google.maps.Geocoder().geocode({ placeId: place_id }, coordinates => {
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
<ion-button style="height: 3em" item-end (click)="checkCoupon()" expand="full" color="primary">{{'contracts.validate' | translate}}</ion-button>
|
||||
</ion-item>
|
||||
</ion-list>
|
||||
<ion-item>
|
||||
<ion-item *ngIf="!paymentBypass">
|
||||
<ion-label>{{'cards.card' | translate}}</ion-label>
|
||||
<ion-select style="max-width:90%" interface="action-sheet" [(ngModel)]="cards_menu" (ionChange)="selected_card($event)">
|
||||
<ion-select-option>Agregar tarjeta</ion-select-option>
|
||||
@@ -49,13 +49,18 @@
|
||||
</ion-select>
|
||||
</ion-item>
|
||||
<form #form="ngForm" id="card_form" (ngSubmit)="createContract(form)" method="post">
|
||||
<ion-item [class.ng-invalid]="!code_check">
|
||||
<ion-item *ngIf="!paymentBypass" [class.ng-invalid]="!code_check">
|
||||
<ion-label position="floating">CVV</ion-label>
|
||||
<ion-input type="password" ngModel name="code" (ionChange)="code_checker($event)" [class.ng-invalid]="!code_check" size="3" maxlength="4"></ion-input>
|
||||
</ion-item><br><br>
|
||||
</ion-item>
|
||||
<ion-note *ngIf="paymentBypass" color="warning" style="display: block; text-align: center; margin: 1em 0;">
|
||||
<b>MODO DE PRUEBA:</b> El pago será simulado
|
||||
</ion-note>
|
||||
<br><br>
|
||||
<ion-button type="submit" expand="full" color="secondary">{{'contracts.hire_confirm' | translate}}</ion-button>
|
||||
</form>
|
||||
<br>
|
||||
<div *ngIf="!paymentBypass">
|
||||
<ion-row class="ion-align-items-center">
|
||||
<ion-col size="4">
|
||||
<img src="/assets/openpay/openpay_color.png" style="padding:0.25em 0.5em"/>
|
||||
@@ -106,4 +111,5 @@
|
||||
<img src="/assets/openpay/bbva.png"/>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</div>
|
||||
</ion-content>
|
||||
|
||||
@@ -33,6 +33,7 @@ export class HirePage implements OnInit {
|
||||
final_amount = null;
|
||||
coupon = null;
|
||||
cards_menu = null;
|
||||
paymentBypass = false;
|
||||
|
||||
constructor(
|
||||
private modalController: ModalController,
|
||||
@@ -59,12 +60,15 @@ export class HirePage implements OnInit {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.paymentBypass = this.env.PAYMENT_BYPASS;
|
||||
if (!this.paymentBypass) {
|
||||
OpenPay.setId(this.env.MERCHANT_ID);
|
||||
OpenPay.setApiKey(this.env.PUBLIC_API_KEY);
|
||||
console.log(OpenPay.getSandboxMode());
|
||||
var deviceDataId = OpenPay.deviceData.setup("card_form");
|
||||
this.getcards();
|
||||
}
|
||||
}
|
||||
|
||||
newcard() {
|
||||
this.navCtrl.navigateForward('/addcard');
|
||||
@@ -141,6 +145,36 @@ export class HirePage implements OnInit {
|
||||
}
|
||||
|
||||
createContract(form: NgForm) {
|
||||
// Si el bypass está activo, enviar con valores dummy
|
||||
if (this.paymentBypass) {
|
||||
this.loadingCtrl.create().then((overlay) => {
|
||||
this.loading = overlay;
|
||||
this.loading.present();
|
||||
});
|
||||
this.ichambaService.createContract(this.postulation_id, this.supplier_id, 'BYPASS', this.coupon, '000', 'BYPASS').subscribe(
|
||||
data => {
|
||||
if (data['type'] == "error") {
|
||||
this.loading.dismiss();
|
||||
this.alertService.presentToast(data['message']);
|
||||
} else if (data['name'] == "used") {
|
||||
this.loading.dismiss();
|
||||
this.alertService.presentToast(this.translateService.instant('contracts.coupon_used'));
|
||||
} else if (data['name'] == "expired") {
|
||||
this.loading.dismiss();
|
||||
this.alertService.presentToast(this.translateService.instant('contracts.coupon_expired'));
|
||||
} else {
|
||||
this.loading.dismiss();
|
||||
this.events.publish('refreshpcontracts', 'data');
|
||||
this.navCtrl.navigateRoot('/contracts/contracted');
|
||||
this.alertService.presentToast(this.translateService.instant('alerts.hire'));
|
||||
}
|
||||
}, error => {
|
||||
this.loading.dismiss();
|
||||
this.alertService.presentToast(this.translateService.instant('alerts.error') + error['status']);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.card_id != "Agregar tarjeta") {
|
||||
if (this.code_check) {
|
||||
let code = form.value.code;
|
||||
|
||||
@@ -56,9 +56,9 @@ ion-item:active:after {
|
||||
</ng-container>
|
||||
<ion-card *ngFor="let pcontract of pcontracts; let i = index">
|
||||
<ion-item>
|
||||
<ion-progress-bar type="indeterminate"></ion-progress-bar>
|
||||
<ion-label>
|
||||
<h2 text-capitalize>{{ pcontract.category }}</h2>
|
||||
<ion-progress-bar type="indeterminate"></ion-progress-bar>
|
||||
<p text-wrap><ion-icon name="search"></ion-icon> {{'contracts.postulating' | translate}}</p>
|
||||
<p text-wrap>{{pcontract.address}}</p>
|
||||
<p text-wrap text-capitalize>{{pcontracts_dates[i]}}</p>
|
||||
|
||||
@@ -16,17 +16,45 @@
|
||||
</ion-item>
|
||||
<br>
|
||||
|
||||
<!-- CATEGORÍAS CON CHIPS -->
|
||||
<ion-label class="chip-label">{{'hero.categories' | translate}}</ion-label>
|
||||
<div class="chips-container">
|
||||
<ion-chip *ngFor="let cat of categories_input" color="primary">
|
||||
<ion-label>{{cat}}</ion-label>
|
||||
<ion-icon name="close-circle" (click)="removeCategory(cat)"></ion-icon>
|
||||
</ion-chip>
|
||||
</div>
|
||||
<ion-item>
|
||||
<ion-label>{{'hero.categories' | translate}}</ion-label>
|
||||
<ion-select [(ngModel)]="categories_input" multiple="true" okText="Aceptar" cancelText="Cancelar" placeholder="{{'hero.categories_placeholder' | translate}}">
|
||||
<ion-select-option *ngFor="let category of categories" [value]="category">{{category}}</ion-select-option>
|
||||
</ion-select>
|
||||
<ion-input
|
||||
[(ngModel)]="categorySearchText"
|
||||
(ionInput)="filterCategories($event)"
|
||||
(ionFocus)="showCategoryList()"
|
||||
(ionBlur)="hideCategoryList()"
|
||||
placeholder="{{'hero.categories_placeholder' | translate}}">
|
||||
</ion-input>
|
||||
</ion-item>
|
||||
<ion-list *ngIf="showCategoryDropdown && filteredCategories.length > 0" class="dropdown-list">
|
||||
<ion-item *ngFor="let category of filteredCategories" button (click)="selectCategory(category)">
|
||||
{{category}}
|
||||
</ion-item>
|
||||
</ion-list>
|
||||
<br>
|
||||
|
||||
<!-- PALABRAS CLAVE CON CHIPS -->
|
||||
<ion-label class="chip-label">{{'hero.keywords' | translate}}</ion-label>
|
||||
<div class="chips-container">
|
||||
<ion-chip *ngFor="let keyword of keywords" color="secondary">
|
||||
<ion-label>{{keyword}}</ion-label>
|
||||
<ion-icon name="close-circle" (click)="removeKeyword(keyword)"></ion-icon>
|
||||
</ion-chip>
|
||||
</div>
|
||||
<ion-item>
|
||||
<ion-label position="floating">{{'hero.keywords' | translate}}</ion-label>
|
||||
<ion-input [(ngModel)]="keywords_text" placeholder="{{'hero.keywords_placeholder' | translate}}"></ion-input>
|
||||
<ion-input
|
||||
[(ngModel)]="keywordInput"
|
||||
(keydown)="onKeywordKeydown($event)"
|
||||
(ionBlur)="addKeyword($event)"
|
||||
placeholder="{{'hero.keywords_placeholder' | translate}}">
|
||||
</ion-input>
|
||||
</ion-item>
|
||||
<ion-note padding>{{'hero.keywords_hint' | translate}}</ion-note>
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
.chip-label {
|
||||
display: block;
|
||||
padding: 10px 16px 5px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: var(--ion-color-medium);
|
||||
}
|
||||
|
||||
.chips-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
padding: 5px 10px;
|
||||
min-height: 20px;
|
||||
gap: 5px;
|
||||
|
||||
ion-chip {
|
||||
margin: 2px;
|
||||
height: 32px;
|
||||
|
||||
ion-label {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
ion-icon {
|
||||
cursor: pointer;
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-list {
|
||||
max-height: 200px;
|
||||
overflow-y: auto;
|
||||
border: 1px solid var(--ion-color-light-shade);
|
||||
border-radius: 8px;
|
||||
margin: 0 16px;
|
||||
background: var(--ion-background-color);
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
||||
|
||||
ion-item {
|
||||
--min-height: 40px;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
--background: var(--ion-color-light);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ion-chip[color="primary"] {
|
||||
--background: var(--ion-color-primary);
|
||||
--color: var(--ion-color-primary-contrast);
|
||||
}
|
||||
|
||||
ion-chip[color="secondary"] {
|
||||
--background: var(--ion-color-secondary);
|
||||
--color: var(--ion-color-secondary-contrast);
|
||||
}
|
||||
|
||||
@@ -17,10 +17,11 @@ export class HeroPage implements OnInit {
|
||||
categories: any[] = [];
|
||||
categories_input: any[] = [];
|
||||
categories_rearranged: any[] = [];
|
||||
keywords: any[] = [];
|
||||
keywords_string: any[] = [];
|
||||
keywords_text: string = '';
|
||||
aux_categories: any[] = [];
|
||||
filteredCategories: any[] = [];
|
||||
categorySearchText: string = '';
|
||||
showCategoryDropdown: boolean = false;
|
||||
keywords: string[] = [];
|
||||
keywordInput: string = '';
|
||||
myPosition: any = {};
|
||||
myAddress: string | null = null;
|
||||
myIntnumber: string | null = null;
|
||||
@@ -42,23 +43,85 @@ export class HeroPage implements OnInit {
|
||||
) { }
|
||||
|
||||
ngOnInit() {
|
||||
/*this.categories = ["carpintero","jardinero","abogado","administrador","agente inmobiliario","agente de seguros","albañil",
|
||||
"arquitecto","asistente personal","becario","cerrajero","chef","chofer","contratista","contador","diseñador de interiores",
|
||||
"cantante","diseñador grafico","edecan","electricista","estilista","servicios financieros","fontanero","fotografo","produccion de videos",
|
||||
"hostess","lavado de tapicerias","aire acondicionado","almacenista","ayudante","azulejero","cerrajero automotriz","cortinas metalicas",
|
||||
"electrico automotriz","entretenimiento","fisioterapeuta","grua","herrero","ingeniero civil","laminado automotriz","limpieza","limpieza del hogar",
|
||||
"mantenimiento","mariachi","masajista","marmolero","mecanico","mercadotecnia","mesero","modelo","musico","niñera","pintor","pintura automotriz",
|
||||
"plomero","programador","publicista","recepcionista","remodelacion","repartidor","reparacion de celulares","reparacion de electronicos","soldador",
|
||||
"tabla roquero","tapicero","tecnico en gas","tuneame la nave","traductor","tutor","vendedor","veterinario","vidrio y aluminio","reparacion de computadoras",
|
||||
"mantenimiento de camiones","consultor","capacitacion","maestro","barbero","agencia de colocacion","agencia de viajes","paseador de perros","banquete",
|
||||
"almacenaje","impermeabilizacion","redes de internet"];*/
|
||||
this.ichambaService.getCategories()
|
||||
.subscribe( categories => {
|
||||
this.categories = categories;
|
||||
this.aux_categories = categories;
|
||||
this.filteredCategories = categories;
|
||||
})
|
||||
}
|
||||
|
||||
// ========== CATEGORÍAS CON CHIPS ==========
|
||||
filterCategories(event: any) {
|
||||
const searchTerm = (event.detail?.value || event.target?.value || '').toLowerCase();
|
||||
this.categorySearchText = searchTerm;
|
||||
if (searchTerm.length > 0) {
|
||||
this.filteredCategories = this.categories.filter(cat =>
|
||||
cat.toLowerCase().includes(searchTerm) && !this.categories_input.includes(cat)
|
||||
);
|
||||
this.showCategoryDropdown = true;
|
||||
} else {
|
||||
this.filteredCategories = this.categories.filter(cat => !this.categories_input.includes(cat));
|
||||
this.showCategoryDropdown = false;
|
||||
}
|
||||
}
|
||||
|
||||
selectCategory(category: string) {
|
||||
if (!this.categories_input.includes(category)) {
|
||||
this.categories_input.push(category);
|
||||
}
|
||||
this.categorySearchText = '';
|
||||
this.showCategoryDropdown = false;
|
||||
this.filteredCategories = this.categories.filter(cat => !this.categories_input.includes(cat));
|
||||
}
|
||||
|
||||
removeCategory(category: string) {
|
||||
const index = this.categories_input.indexOf(category);
|
||||
if (index > -1) {
|
||||
this.categories_input.splice(index, 1);
|
||||
}
|
||||
this.filteredCategories = this.categories.filter(cat => !this.categories_input.includes(cat));
|
||||
}
|
||||
|
||||
showCategoryList() {
|
||||
this.filteredCategories = this.categories.filter(cat => !this.categories_input.includes(cat));
|
||||
this.showCategoryDropdown = true;
|
||||
}
|
||||
|
||||
hideCategoryList() {
|
||||
setTimeout(() => {
|
||||
this.showCategoryDropdown = false;
|
||||
}, 200);
|
||||
}
|
||||
|
||||
// ========== PALABRAS CLAVE CON CHIPS ==========
|
||||
addKeyword(event?: any) {
|
||||
const value = this.keywordInput?.trim();
|
||||
if (value && value.length > 0) {
|
||||
// Separar por comas si hay varias palabras
|
||||
const newKeywords = value.split(',').map((k: string) => k.trim()).filter((k: string) => k.length > 0);
|
||||
newKeywords.forEach((keyword: string) => {
|
||||
if (!this.keywords.includes(keyword)) {
|
||||
this.keywords.push(keyword);
|
||||
}
|
||||
});
|
||||
this.keywordInput = '';
|
||||
}
|
||||
}
|
||||
|
||||
onKeywordKeydown(event: KeyboardEvent) {
|
||||
if (event.key === 'Enter' || event.key === ',') {
|
||||
event.preventDefault();
|
||||
this.addKeyword();
|
||||
}
|
||||
}
|
||||
|
||||
removeKeyword(keyword: string) {
|
||||
const index = this.keywords.indexOf(keyword);
|
||||
if (index > -1) {
|
||||
this.keywords.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
dismissHero() {
|
||||
this.navCtrl.navigateRoot('/landing');
|
||||
}
|
||||
@@ -103,22 +166,18 @@ export class HeroPage implements OnInit {
|
||||
}
|
||||
|
||||
addHero(){
|
||||
// categories_input is now an array of values directly from ion-select
|
||||
this.categories_rearranged = this.categories_input.slice();
|
||||
// Preparar categorías y keywords
|
||||
const categoriesString = this.categories_input.join(',');
|
||||
const keywordsString = this.keywords.length > 0 ? this.keywords.join(', ') : null;
|
||||
|
||||
// keywords_text is now a string, split by comma
|
||||
if (this.keywords_text && this.keywords_text.trim().length > 0) {
|
||||
this.keywords_string = this.keywords_text.split(',').map(k => k.trim()).filter(k => k.length > 0);
|
||||
}
|
||||
|
||||
if (this.name && this.categories_input && this.myAddress && this.myPosition.latitude && this.myPosition.longitude && this.selectedReference){
|
||||
if (this.name && this.categories_input.length > 0 && this.myAddress && this.myPosition.latitude && this.myPosition.longitude && this.selectedReference){
|
||||
if (this.selectedReference == 5 && this.reference) {
|
||||
this.loadingCtrl.create().then((overlay) => {
|
||||
this.loading = overlay;
|
||||
this.loading.present();
|
||||
});
|
||||
|
||||
this.ichambaService.addHero(this.name, this.categories_rearranged.join(','), (this.keywords_string.join(', ') == "" ? null : this.keywords_string.join(', ')), this.myAddress, this.myPosition.latitude, this.myPosition.longitude, this.selectedReference, this.reference).subscribe(
|
||||
this.ichambaService.addHero(this.name, categoriesString, keywordsString, this.myAddress, this.myPosition.latitude, this.myPosition.longitude, this.selectedReference, this.reference).subscribe(
|
||||
data => {
|
||||
this.loading.dismiss();
|
||||
this.alertService.presentToast(data['message']);
|
||||
@@ -133,7 +192,7 @@ export class HeroPage implements OnInit {
|
||||
this.loading.present();
|
||||
});
|
||||
|
||||
this.ichambaService.addHero(this.name, this.categories_rearranged.join(','), (this.keywords_string.join(', ') == "" ? null : this.keywords_string.join(', ')), this.myAddress, this.myPosition.latitude, this.myPosition.longitude, this.selectedReference, this.reference).subscribe(
|
||||
this.ichambaService.addHero(this.name, categoriesString, keywordsString, this.myAddress, this.myPosition.latitude, this.myPosition.longitude, this.selectedReference, this.reference).subscribe(
|
||||
data => {
|
||||
this.loading.dismiss();
|
||||
this.alertService.presentToast(data['message']);
|
||||
|
||||
@@ -4,11 +4,14 @@ import { Injectable } from '@angular/core';
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class EnvService {
|
||||
API_URL = 'http://192.168.10.207:8080/api/';
|
||||
API_URL = 'https://jobhero-api.consultoria-as.com/api/';
|
||||
SECRET = 'wBIIKuDbrxNKzQhAUGiZLoaoQ4MichAN3wP2AP7B';
|
||||
MERCHANT_ID = 'm9k4beuso5az0wjqztvt';
|
||||
PUBLIC_API_KEY = 'pk_9465179493384689a8d2da9adc825411';
|
||||
ONESIGNAL_APP_ID = 'c854ae89-7ff7-4216-a70e-5fdff0cd8e10';
|
||||
|
||||
// Bypass de pago para pruebas (cambiar a false para producción)
|
||||
PAYMENT_BYPASS = true;
|
||||
|
||||
constructor() { }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user