feat: Side menu dinámico, login social y traducciones hero
- app.component: menú lateral con roles de usuario, ChangeDetectorRef para re-render tras login, integración OneSignal al iniciar sesión - auth/login: botones Google y Apple con estilos, navegación corregida - auth/register y forgot: mejoras de UX y navegación - landing: sombra en botones del footer - i18n: claves hero (select, bank, bank_account, fee, required) en es/en Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -8,12 +8,46 @@
|
|||||||
</ion-header>
|
</ion-header>
|
||||||
<ion-content>
|
<ion-content>
|
||||||
<ion-list>
|
<ion-list>
|
||||||
<ion-menu-toggle auto-hide="false" *ngFor="let p of appPages">
|
<ion-menu-toggle auto-hide="false" [class.ion-hide]="userRole === 0">
|
||||||
<ion-item [routerDirection]="'root'" [routerLink]="[p.url]">
|
<ion-item [routerDirection]="'root'" [routerLink]="['/dashboard']">
|
||||||
<ion-icon slot="start" [name]="p.icon"></ion-icon>
|
<ion-icon slot="start" name="home"></ion-icon>
|
||||||
<ion-label>
|
<ion-label>{{'menu.home' | translate}}</ion-label>
|
||||||
{{p.title}}
|
</ion-item>
|
||||||
</ion-label>
|
</ion-menu-toggle>
|
||||||
|
<ion-menu-toggle auto-hide="false" [class.ion-hide]="userRole === 0">
|
||||||
|
<ion-item [routerDirection]="'root'" [routerLink]="['/cards']">
|
||||||
|
<ion-icon slot="start" name="card"></ion-icon>
|
||||||
|
<ion-label>{{'menu.cards' | translate}}</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
</ion-menu-toggle>
|
||||||
|
<ion-menu-toggle auto-hide="false" [class.ion-hide]="userRole < 2">
|
||||||
|
<ion-item [routerDirection]="'root'" [routerLink]="['/postulations']">
|
||||||
|
<ion-icon slot="start" name="hammer"></ion-icon>
|
||||||
|
<ion-label>{{'menu.postulations' | translate}}</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
</ion-menu-toggle>
|
||||||
|
<ion-menu-toggle auto-hide="false" [class.ion-hide]="userRole === 0">
|
||||||
|
<ion-item [routerDirection]="'root'" [routerLink]="['/contracts']">
|
||||||
|
<ion-icon slot="start" name="file-tray-full"></ion-icon>
|
||||||
|
<ion-label>{{'menu.contracts' | translate}}</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
</ion-menu-toggle>
|
||||||
|
<ion-menu-toggle auto-hide="false" [class.ion-hide]="userRole === 0">
|
||||||
|
<ion-item [routerDirection]="'root'" [routerLink]="['/faq']">
|
||||||
|
<ion-icon slot="start" name="information-circle"></ion-icon>
|
||||||
|
<ion-label>{{'menu.faq' | translate}}</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
</ion-menu-toggle>
|
||||||
|
<ion-menu-toggle auto-hide="false" [class.ion-hide]="userRole < 2">
|
||||||
|
<ion-item [routerDirection]="'root'" [routerLink]="['/start']">
|
||||||
|
<ion-icon slot="start" name="send"></ion-icon>
|
||||||
|
<ion-label>{{'menu.start' | translate}}</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
</ion-menu-toggle>
|
||||||
|
<ion-menu-toggle auto-hide="false" [class.ion-hide]="userRole !== 1">
|
||||||
|
<ion-item [routerDirection]="'root'" [routerLink]="['/hero']">
|
||||||
|
<ion-icon slot="start" name="ribbon"></ion-icon>
|
||||||
|
<ion-label>{{'menu.hero' | translate}}</ion-label>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
</ion-menu-toggle>
|
</ion-menu-toggle>
|
||||||
<ion-item (click)="logout()">
|
<ion-item (click)="logout()">
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component, OnInit, ChangeDetectorRef } from '@angular/core';
|
||||||
import { Platform, NavController, LoadingController } from '@ionic/angular';
|
import { Platform, NavController, LoadingController } from '@ionic/angular';
|
||||||
import { EventService } from './services/event.service';
|
import { EventService } from './services/event.service';
|
||||||
import { StatusBar, Style } from '@capacitor/status-bar';
|
import { StatusBar, Style } from '@capacitor/status-bar';
|
||||||
@@ -13,17 +13,17 @@ import { OneSignalService } from './services/onesignal.service';
|
|||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
templateUrl: 'app.component.html'
|
templateUrl: 'app.component.html',
|
||||||
|
standalone: false
|
||||||
})
|
})
|
||||||
export class AppComponent {
|
export class AppComponent implements OnInit {
|
||||||
|
|
||||||
private loading: any;
|
private loading: any;
|
||||||
|
userRole: number = 0;
|
||||||
public appPages: any[] = [];
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private platform: Platform,
|
private platform: Platform,
|
||||||
private authService: AuthService,
|
public authService: AuthService,
|
||||||
private languageService: LanguageService,
|
private languageService: LanguageService,
|
||||||
private translateService: TranslateService,
|
private translateService: TranslateService,
|
||||||
private navCtrl: NavController,
|
private navCtrl: NavController,
|
||||||
@@ -31,75 +31,20 @@ export class AppComponent {
|
|||||||
private alertService: AlertService,
|
private alertService: AlertService,
|
||||||
private loadingCtrl: LoadingController,
|
private loadingCtrl: LoadingController,
|
||||||
private oneSignalService: OneSignalService,
|
private oneSignalService: OneSignalService,
|
||||||
|
private cdr: ChangeDetectorRef,
|
||||||
) {
|
) {
|
||||||
this.initializeApp();
|
this.initializeApp();
|
||||||
this.events.subscribe('set_role', role => {
|
this.events.subscribe('set_role', role => {
|
||||||
// Set OneSignal user tags when role is set (user logged in)
|
this.userRole = role ?? 0;
|
||||||
|
this.cdr.detectChanges();
|
||||||
this.setupOneSignalUser(role);
|
this.setupOneSignalUser(role);
|
||||||
if (role >= 2){
|
|
||||||
this.appPages = [
|
|
||||||
{
|
|
||||||
title: this.translateService.instant('menu.home'),
|
|
||||||
url: '/dashboard',
|
|
||||||
icon: 'home'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: this.translateService.instant('menu.cards'),
|
|
||||||
url: '/cards',
|
|
||||||
icon: 'card'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: this.translateService.instant('menu.postulations'),
|
|
||||||
url: '/postulations',
|
|
||||||
icon: 'hammer'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: this.translateService.instant('menu.contracts'),
|
|
||||||
url: '/contracts',
|
|
||||||
icon: 'filing'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: this.translateService.instant('menu.faq'),
|
|
||||||
url: '/faq',
|
|
||||||
icon: 'information-circle'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: this.translateService.instant('menu.start'),
|
|
||||||
url: '/start',
|
|
||||||
icon: 'send'
|
|
||||||
}
|
|
||||||
];
|
|
||||||
} else {
|
|
||||||
this.appPages = [
|
|
||||||
{
|
|
||||||
title: this.translateService.instant('menu.home'),
|
|
||||||
url: '/dashboard',
|
|
||||||
icon: 'home'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: this.translateService.instant('menu.cards'),
|
|
||||||
url: '/cards',
|
|
||||||
icon: 'card'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: this.translateService.instant('menu.contracts'),
|
|
||||||
url: '/contracts',
|
|
||||||
icon: 'filing'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: this.translateService.instant('menu.faq'),
|
|
||||||
url: '/faq',
|
|
||||||
icon: 'information-circle'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: this.translateService.instant('menu.hero'),
|
|
||||||
url: '/hero',
|
|
||||||
icon: 'ribbon'
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.userRole = this.authService.userRole;
|
||||||
|
}
|
||||||
|
|
||||||
async initializeApp() {
|
async initializeApp() {
|
||||||
await this.platform.ready();
|
await this.platform.ready();
|
||||||
|
|
||||||
@@ -114,7 +59,6 @@ export class AppComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.languageService.getDefaultLanguage();
|
this.languageService.getDefaultLanguage();
|
||||||
this.authService.getToken();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async setupOneSignalUser(role: number) {
|
private async setupOneSignalUser(role: number) {
|
||||||
|
|||||||
@@ -8,8 +8,8 @@
|
|||||||
<ion-title>{{'auth.forgot' | translate}}</ion-title>
|
<ion-title>{{'auth.forgot' | translate}}</ion-title>
|
||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
<ion-content padding>
|
<ion-content class="ion-padding">
|
||||||
<p text-wrap>{{'auth.forgot_instructions' | translate}}</p><br>
|
<p class="ion-text-wrap">{{'auth.forgot_instructions' | translate}}</p><br>
|
||||||
<form #form="ngForm" (ngSubmit)="forgot(form)" method="post">
|
<form #form="ngForm" (ngSubmit)="forgot(form)" method="post">
|
||||||
<ion-item>
|
<ion-item>
|
||||||
<ion-label position="floating">{{'auth.email' | translate}}</ion-label>
|
<ion-label position="floating">{{'auth.email' | translate}}</ion-label>
|
||||||
|
|||||||
@@ -1,52 +1,52 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { NavController, LoadingController } from '@ionic/angular';
|
import { NavController, LoadingController } from '@ionic/angular';
|
||||||
import { NgForm } from '@angular/forms';
|
import { NgForm } from '@angular/forms';
|
||||||
import { AuthService } from 'src/app/services/auth.service';
|
|
||||||
import { AlertService } from 'src/app/services/alert.service';
|
import { AlertService } from 'src/app/services/alert.service';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
import { FirebaseAuthService } from 'src/app/services/firebase-auth.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-forgot',
|
selector: 'app-forgot',
|
||||||
templateUrl: './forgot.page.html',
|
templateUrl: './forgot.page.html',
|
||||||
styleUrls: ['./forgot.page.scss'],
|
styleUrls: ['./forgot.page.scss'],
|
||||||
|
standalone: false
|
||||||
})
|
})
|
||||||
export class ForgotPage implements OnInit {
|
export class ForgotPage implements OnInit {
|
||||||
|
|
||||||
private loading;
|
private loading: HTMLIonLoadingElement | null = null;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private authService: AuthService,
|
private firebaseAuthService: FirebaseAuthService,
|
||||||
private navCtrl: NavController,
|
private navCtrl: NavController,
|
||||||
private alertService: AlertService,
|
private alertService: AlertService,
|
||||||
private translateService: TranslateService,
|
private translateService: TranslateService,
|
||||||
private loadingCtrl: LoadingController
|
private loadingCtrl: LoadingController
|
||||||
) { }
|
) { }
|
||||||
ngOnInit() {
|
|
||||||
}
|
ngOnInit() { }
|
||||||
// Dismiss Forgot Modal
|
|
||||||
dismissForgot() {
|
dismissForgot() {
|
||||||
this.navCtrl.back();
|
this.navCtrl.back();
|
||||||
}
|
}
|
||||||
// On Register button tap, dismiss login modal and open register modal
|
|
||||||
|
|
||||||
forgot(form: NgForm) {
|
async forgot(form: NgForm) {
|
||||||
this.loadingCtrl.create().then((overlay) => {
|
this.loading = await this.loadingCtrl.create();
|
||||||
this.loading = overlay;
|
await this.loading.present();
|
||||||
this.loading.present();
|
|
||||||
});
|
try {
|
||||||
this.authService.forgot(form.value.email).subscribe(
|
await this.firebaseAuthService.sendPasswordReset(form.value.email);
|
||||||
data => {
|
if (this.loading) this.loading.dismiss();
|
||||||
this.loading.dismiss();
|
this.alertService.presentToast(this.translateService.instant('alerts.reset_pass'));
|
||||||
|
this.dismissForgot();
|
||||||
|
} catch (e: any) {
|
||||||
|
if (this.loading) this.loading.dismiss();
|
||||||
|
if (e.code === 'auth/user-not-found') {
|
||||||
|
// Por seguridad mostramos el mismo mensaje aunque no exista el usuario
|
||||||
this.alertService.presentToast(this.translateService.instant('alerts.reset_pass'));
|
this.alertService.presentToast(this.translateService.instant('alerts.reset_pass'));
|
||||||
},
|
|
||||||
error => {
|
|
||||||
this.loading.dismiss();
|
|
||||||
this.alertService.presentToast(this.translateService.instant('alerts.error') + error['message']);
|
|
||||||
console.log(error);
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
this.dismissForgot();
|
this.dismissForgot();
|
||||||
|
} else {
|
||||||
|
this.alertService.presentToast(this.translateService.instant('alerts.error') + e.message);
|
||||||
}
|
}
|
||||||
);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
<ion-title>{{'auth.login' | translate}}</ion-title>
|
<ion-title>{{'auth.login' | translate}}</ion-title>
|
||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
<ion-content padding>
|
<ion-content class="ion-padding">
|
||||||
<form #form="ngForm" (ngSubmit)="login(form)" method="post">
|
<form #form="ngForm" (ngSubmit)="login(form)" method="post">
|
||||||
<ion-item>
|
<ion-item>
|
||||||
<ion-label position="floating">{{'auth.email' | translate}}</ion-label>
|
<ion-label position="floating">{{'auth.email' | translate}}</ion-label>
|
||||||
@@ -22,11 +22,27 @@
|
|||||||
<br>
|
<br>
|
||||||
<ion-button type="submit" expand="full" color="primary">{{'auth.login' | translate}}</ion-button>
|
<ion-button type="submit" expand="full" color="primary">{{'auth.login' | translate}}</ion-button>
|
||||||
</form>
|
</form>
|
||||||
<ion-text><p text-center (click)="forgotModal()"><u>{{'auth.forgot' | translate}}</u></p></ion-text>
|
<ion-text><p class="ion-text-center" (click)="forgotModal()"><u>{{'auth.forgot' | translate}}</u></p></ion-text>
|
||||||
<br><br>
|
<br><br>
|
||||||
<ion-button expand="full" color="facebook" (click)="loginFacebook()">{{'auth.fb_login' | translate}}</ion-button>
|
<!-- Google Sign-In — branding oficial: fondo blanco, logo G coloreado, borde gris -->
|
||||||
<ion-button expand="full" color="danger" (click)="loginGoogle()">{{'auth.google_login' | translate}}</ion-button>
|
<button class="btn-social btn-google" (click)="loginGoogle()">
|
||||||
<p text-center>{{'auth.signup_ad' | translate}}</p>
|
<svg class="btn-social__icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z" fill="#4285F4"/>
|
||||||
|
<path d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z" fill="#34A853"/>
|
||||||
|
<path d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l3.66-2.84z" fill="#FBBC05"/>
|
||||||
|
<path d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z" fill="#EA4335"/>
|
||||||
|
</svg>
|
||||||
|
<span class="btn-social__label">{{'auth.google_login' | translate}}</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- Apple Sign-In — branding oficial: fondo negro, logo Apple blanco, SF font -->
|
||||||
|
<button class="btn-social btn-apple" (click)="loginApple()">
|
||||||
|
<svg class="btn-social__icon btn-social__icon--apple" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M17.05 20.28c-.98.95-2.05.8-3.08.35-1.09-.46-2.09-.48-3.24 0-1.44.62-2.2.44-3.06-.35C2.79 15.25 3.51 7.7 9.05 7.4c1.42.07 2.4.78 3.23.8 1.22-.24 2.39-.93 3.68-.84 1.56.12 2.73.72 3.5 1.9-3.22 1.93-2.46 5.91.59 7.03-.69 1.55-1.6 3.08-3 4zM12.03 7.25c-.15-2.23 1.66-4.07 3.74-4.25.29 2.58-2.34 4.5-3.74 4.25z" fill="#FFFFFF"/>
|
||||||
|
</svg>
|
||||||
|
<span class="btn-social__label">{{'auth.apple_login' | translate}}</span>
|
||||||
|
</button>
|
||||||
|
<p class="ion-text-center">{{'auth.signup_ad' | translate}}</p>
|
||||||
<ion-button expand="full" color="secondary" (click)="registerModal()">{{'auth.signup' | translate}}</ion-button>
|
<ion-button expand="full" color="secondary" (click)="registerModal()">{{'auth.signup' | translate}}</ion-button>
|
||||||
<ion-text><p text-center>{{'auth.terms_1' | translate}}<u (click)="openTerms()">{{'auth.terms_2' | translate}}</u>{{'auth.terms_3' | translate}}</p></ion-text>
|
<ion-text><p class="ion-text-center">{{'auth.terms_1' | translate}}<u (click)="openTerms()">{{'auth.terms_2' | translate}}</u>{{'auth.terms_3' | translate}}</p></ion-text>
|
||||||
</ion-content>
|
</ion-content>
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
.btn-social {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
height: 44px;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
letter-spacing: 0.06em;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
padding: 0 12px;
|
||||||
|
transition: box-shadow 0.2s ease;
|
||||||
|
|
||||||
|
&__icon {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
margin-right: 12px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
&--apple {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__label {
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
margin-right: 32px; // compensa el ancho del icono para centrar visualmente
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
box-shadow: inset 0 0 0 2px rgba(0, 0, 0, 0.15);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Google: fondo blanco, borde gris, texto oscuro
|
||||||
|
.btn-google {
|
||||||
|
background-color: #ffffff;
|
||||||
|
border: 1px solid #DADCE0;
|
||||||
|
color: #3c4043;
|
||||||
|
font-family: 'Roboto', sans-serif;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apple: fondo negro, texto blanco, font del sistema
|
||||||
|
.btn-apple {
|
||||||
|
background-color: #000000;
|
||||||
|
color: #ffffff;
|
||||||
|
font-family: -apple-system, 'SF Pro Display', BlinkMacSystemFont, sans-serif;
|
||||||
|
border-radius: 6px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #1a1a1a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,22 +4,24 @@ import { NgForm } from '@angular/forms';
|
|||||||
import { AuthService } from 'src/app/services/auth.service';
|
import { AuthService } from 'src/app/services/auth.service';
|
||||||
import { AlertService } from 'src/app/services/alert.service';
|
import { AlertService } from 'src/app/services/alert.service';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { FacebookLogin, FacebookLoginResponse } from '@capacitor-community/facebook-login';
|
import { FirebaseAuthService } from 'src/app/services/firebase-auth.service';
|
||||||
import { GoogleAuth } from '@codetrix-studio/capacitor-google-auth';
|
|
||||||
import { Browser } from '@capacitor/browser';
|
import { Browser } from '@capacitor/browser';
|
||||||
|
import { firstValueFrom } from 'rxjs';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-login',
|
selector: 'app-login',
|
||||||
templateUrl: './login.page.html',
|
templateUrl: './login.page.html',
|
||||||
styleUrls: ['./login.page.scss']
|
styleUrls: ['./login.page.scss'],
|
||||||
|
standalone: false
|
||||||
})
|
})
|
||||||
export class LoginPage implements OnInit {
|
export class LoginPage implements OnInit {
|
||||||
|
|
||||||
private loading: any;
|
private loading: HTMLIonLoadingElement | null = null;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private authService: AuthService,
|
private authService: AuthService,
|
||||||
|
private firebaseAuthService: FirebaseAuthService,
|
||||||
private navCtrl: NavController,
|
private navCtrl: NavController,
|
||||||
private alertService: AlertService,
|
private alertService: AlertService,
|
||||||
private translateService: TranslateService,
|
private translateService: TranslateService,
|
||||||
@@ -45,68 +47,73 @@ export class LoginPage implements OnInit {
|
|||||||
this.loading = await this.loadingCtrl.create();
|
this.loading = await this.loadingCtrl.create();
|
||||||
await this.loading.present();
|
await this.loading.present();
|
||||||
|
|
||||||
this.authService.login(form.value.email, form.value.password).subscribe(
|
try {
|
||||||
data => {
|
const idToken = await this.firebaseAuthService.signInWithEmail(
|
||||||
if (this.loading) this.loading.dismiss();
|
form.value.email,
|
||||||
},
|
form.value.password
|
||||||
error => {
|
);
|
||||||
if (this.loading) this.loading.dismiss();
|
|
||||||
if (JSON.stringify(error['status']) == '401') {
|
this.authService.loginWithFirebase(idToken).subscribe(
|
||||||
this.alertService.presentToast(this.translateService.instant('alerts.login_error'));
|
(data: any) => {},
|
||||||
}
|
(error: any) => {
|
||||||
else {
|
if (this.loading) this.loading.dismiss();
|
||||||
this.alertService.presentToast(this.translateService.instant('alerts.error') + error['message']);
|
if (JSON.stringify(error['status']) == '401') {
|
||||||
console.log(error);
|
this.alertService.presentToast(this.translateService.instant('alerts.login_error'));
|
||||||
}
|
} else {
|
||||||
},
|
this.alertService.presentToast(this.translateService.instant('alerts.error') + error['message']);
|
||||||
() => {
|
}
|
||||||
if (this.loading) this.loading.dismiss();
|
},
|
||||||
this.dismissLogin();
|
() => { this.navigateAfterLogin(); }
|
||||||
this.navCtrl.navigateRoot('/dashboard');
|
);
|
||||||
this.alertService.presentToast(this.translateService.instant('alerts.login'));
|
} catch (e: any) {
|
||||||
}
|
if (this.loading) this.loading.dismiss();
|
||||||
);
|
const msg = this.getFirebaseErrorMessage(e.code);
|
||||||
|
this.alertService.presentToast(msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async loginFacebook() {
|
private async navigateAfterLogin() {
|
||||||
this.loading = await this.loadingCtrl.create();
|
try {
|
||||||
await this.loading.present();
|
await firstValueFrom(this.authService.user());
|
||||||
|
} catch { }
|
||||||
|
if (this.loading) this.loading.dismiss();
|
||||||
|
this.navCtrl.navigateRoot('/dashboard');
|
||||||
|
this.alertService.presentToast(this.translateService.instant('alerts.login'));
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
private getFirebaseErrorMessage(code: string): string {
|
||||||
// Login with permissions
|
switch (code) {
|
||||||
const result = await FacebookLogin.login({ permissions: ['public_profile', 'email'] });
|
case 'auth/wrong-password':
|
||||||
|
case 'auth/user-not-found':
|
||||||
|
case 'auth/invalid-credential':
|
||||||
|
return this.translateService.instant('alerts.login_error');
|
||||||
|
case 'auth/too-many-requests':
|
||||||
|
return this.translateService.instant('alerts.too_many_requests');
|
||||||
|
default:
|
||||||
|
return this.translateService.instant('alerts.error') + code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (result.accessToken) {
|
async loginApple() {
|
||||||
// Get user ID and Token
|
this.loading = await this.loadingCtrl.create();
|
||||||
const fb_id = result.accessToken.userId;
|
await this.loading.present();
|
||||||
const fb_token = result.accessToken.token;
|
|
||||||
|
|
||||||
console.log("ID: " + fb_id);
|
try {
|
||||||
console.log("Token: " + fb_token);
|
const idToken = await this.firebaseAuthService.signInWithApple();
|
||||||
|
|
||||||
this.authService.login_register_fb(fb_token, fb_id).subscribe(
|
this.authService.loginWithFirebase(idToken).subscribe(
|
||||||
data => {
|
(data: any) => {},
|
||||||
},
|
(error: any) => {
|
||||||
error => {
|
if (this.loading) this.loading.dismiss();
|
||||||
this.loading.dismiss();
|
this.alertService.presentToast(this.translateService.instant('alerts.error') + error);
|
||||||
this.alertService.presentToast(this.translateService.instant('alerts.error') + error);
|
console.log(error);
|
||||||
console.log(error);
|
},
|
||||||
},
|
() => { this.navigateAfterLogin(); }
|
||||||
() => {
|
);
|
||||||
this.loading.dismiss();
|
} catch (e) {
|
||||||
this.dismissLogin();
|
if (this.loading) this.loading.dismiss();
|
||||||
this.navCtrl.navigateRoot('/dashboard');
|
this.alertService.presentToast(this.translateService.instant('alerts.error') + e);
|
||||||
this.alertService.presentToast(this.translateService.instant('alerts.login'));
|
}
|
||||||
}
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
this.loading.dismiss();
|
|
||||||
this.alertService.presentToast(this.translateService.instant('alerts.timeout_error'));
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
this.loading.dismiss();
|
|
||||||
this.alertService.presentToast(this.translateService.instant('alerts.error') + e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async loginGoogle() {
|
async loginGoogle() {
|
||||||
@@ -114,32 +121,19 @@ export class LoginPage implements OnInit {
|
|||||||
await this.loading.present();
|
await this.loading.present();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await GoogleAuth.signIn();
|
const idToken = await this.firebaseAuthService.signInWithGoogle();
|
||||||
console.log(res);
|
|
||||||
|
|
||||||
const google_id = res.id;
|
this.authService.loginWithFirebase(idToken).subscribe(
|
||||||
const google_token = res.authentication.accessToken;
|
(data: any) => {},
|
||||||
|
(error: any) => {
|
||||||
console.log("ID: " + google_id);
|
if (this.loading) this.loading.dismiss();
|
||||||
console.log("Token: " + google_token);
|
|
||||||
|
|
||||||
this.authService.login_register_googlePlus(google_token, google_id).subscribe(
|
|
||||||
data => {
|
|
||||||
},
|
|
||||||
error => {
|
|
||||||
this.loading.dismiss();
|
|
||||||
this.alertService.presentToast(this.translateService.instant('alerts.error') + error);
|
this.alertService.presentToast(this.translateService.instant('alerts.error') + error);
|
||||||
console.log(error);
|
console.log(error);
|
||||||
},
|
},
|
||||||
() => {
|
() => { this.navigateAfterLogin(); }
|
||||||
this.loading.dismiss();
|
|
||||||
this.dismissLogin();
|
|
||||||
this.navCtrl.navigateRoot('/dashboard');
|
|
||||||
this.alertService.presentToast(this.translateService.instant('alerts.login'));
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.loading.dismiss();
|
if (this.loading) this.loading.dismiss();
|
||||||
this.alertService.presentToast(this.translateService.instant('alerts.error') + err);
|
this.alertService.presentToast(this.translateService.instant('alerts.error') + err);
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
<ion-title>{{'auth.signup' | translate}}</ion-title>
|
<ion-title>{{'auth.signup' | translate}}</ion-title>
|
||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
<ion-content padding>
|
<ion-content class="ion-padding">
|
||||||
<form #form="ngForm" (ngSubmit)="register(form)" method="post">
|
<form #form="ngForm" (ngSubmit)="register(form)" method="post">
|
||||||
<ion-item>
|
<ion-item>
|
||||||
<ion-label position="floating">{{'auth.name' | translate}}</ion-label>
|
<ion-label position="floating">{{'auth.name' | translate}}</ion-label>
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
<br><br>
|
<br><br>
|
||||||
<ion-row>
|
<ion-row>
|
||||||
<ion-col size="9.5">
|
<ion-col size="9.5">
|
||||||
<p text-center style="margin-bottom:0;margin-top:0.25em;color:#4d4d4d">{{'auth.terms_1' | translate}}<u (click)="openTerms()">{{'auth.terms_2' | translate}}</u>{{'auth.terms_3' | translate}}</p>
|
<p class="ion-text-center" style="margin-bottom:0;margin-top:0.25em;color:#4d4d4d">{{'auth.terms_1' | translate}}<u (click)="openTerms()">{{'auth.terms_2' | translate}}</u>{{'auth.terms_3' | translate}}</p>
|
||||||
</ion-col>
|
</ion-col>
|
||||||
<ion-col size="2.5">
|
<ion-col size="2.5">
|
||||||
<ion-item lines="none">
|
<ion-item lines="none">
|
||||||
@@ -48,6 +48,6 @@
|
|||||||
<br>
|
<br>
|
||||||
<ion-button type="submit" expand="full" color="secondary">{{'auth.signup' | translate}}</ion-button>
|
<ion-button type="submit" expand="full" color="secondary">{{'auth.signup' | translate}}</ion-button>
|
||||||
</form>
|
</form>
|
||||||
<br><p text-center>{{'auth.login_ad' | translate}}</p>
|
<br><p class="ion-text-center">{{'auth.login_ad' | translate}}</p>
|
||||||
<ion-button expand="full" color="primary" (click)="loginModal()">{{'auth.login' | translate}}</ion-button>
|
<ion-button expand="full" color="primary" (click)="loginModal()">{{'auth.login' | translate}}</ion-button>
|
||||||
</ion-content>
|
</ion-content>
|
||||||
|
|||||||
@@ -4,85 +4,93 @@ import { AuthService } from 'src/app/services/auth.service';
|
|||||||
import { NgForm } from '@angular/forms';
|
import { NgForm } from '@angular/forms';
|
||||||
import { AlertService } from 'src/app/services/alert.service';
|
import { AlertService } from 'src/app/services/alert.service';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
import { FirebaseAuthService } from 'src/app/services/firebase-auth.service';
|
||||||
import { Browser } from '@capacitor/browser';
|
import { Browser } from '@capacitor/browser';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-register',
|
selector: 'app-register',
|
||||||
templateUrl: './register.page.html',
|
templateUrl: './register.page.html',
|
||||||
styleUrls: ['./register.page.scss'],
|
styleUrls: ['./register.page.scss'],
|
||||||
|
standalone: false
|
||||||
})
|
})
|
||||||
export class RegisterPage implements OnInit {
|
export class RegisterPage implements OnInit {
|
||||||
|
|
||||||
loading: any = null;
|
loading: HTMLIonLoadingElement | null = null;
|
||||||
terms = false;
|
terms = false;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private authService: AuthService,
|
private authService: AuthService,
|
||||||
|
private firebaseAuthService: FirebaseAuthService,
|
||||||
private translateService: TranslateService,
|
private translateService: TranslateService,
|
||||||
private navCtrl: NavController,
|
private navCtrl: NavController,
|
||||||
private loadingCtrl: LoadingController,
|
private loadingCtrl: LoadingController,
|
||||||
private alertService: AlertService
|
private alertService: AlertService
|
||||||
) { }
|
) { }
|
||||||
ngOnInit() {
|
|
||||||
}
|
ngOnInit() { }
|
||||||
// Dismiss Register Modal
|
|
||||||
dismissRegister() {
|
dismissRegister() {
|
||||||
this.navCtrl.navigateRoot('/landing');
|
this.navCtrl.navigateRoot('/landing');
|
||||||
}
|
}
|
||||||
// On Login button tap, dismiss Register modal and open login Modal
|
|
||||||
loginModal() {
|
loginModal() {
|
||||||
this.navCtrl.navigateForward('/login');
|
this.navCtrl.navigateForward('/login');
|
||||||
}
|
}
|
||||||
|
|
||||||
updateChecked () {
|
updateChecked() {
|
||||||
if (this.terms == true) {
|
this.terms = !this.terms;
|
||||||
this.terms = false;
|
|
||||||
console.log(this.terms);
|
|
||||||
} else {
|
|
||||||
this.terms = true;
|
|
||||||
console.log(this.terms);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
register(form: NgForm) {
|
async register(form: NgForm) {
|
||||||
|
if (!this.terms) {
|
||||||
if (this.terms == true) {
|
|
||||||
if (form.value.name && form.value.email && form.value.phone && form.value.password && form.value.password1) {
|
|
||||||
if (form.value.password == form.value.password1) {
|
|
||||||
this.loadingCtrl.create().then((overlay) => {
|
|
||||||
this.loading = overlay;
|
|
||||||
this.loading.present();
|
|
||||||
});
|
|
||||||
this.authService.register(form.value.name, form.value.email, form.value.phone, form.value.password).subscribe(
|
|
||||||
data => {
|
|
||||||
this.loading.dismiss();
|
|
||||||
this.alertService.presentToast(this.translateService.instant('alerts.signup'));
|
|
||||||
},
|
|
||||||
error => {
|
|
||||||
if (JSON.stringify(error['status']) == '422') {
|
|
||||||
this.loading.dismiss();
|
|
||||||
this.alertService.presentToast(this.translateService.instant('alerts.signup_error'));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.loading.dismiss();
|
|
||||||
console.log(error);
|
|
||||||
this.alertService.presentToast(this.translateService.instant('alerts.error') + error['message']);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
this.alertService.presentToast(this.translateService.instant('alerts.signup_error_1'));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.alertService.presentToast(this.translateService.instant('alerts.signup_error_2'));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.alertService.presentToast(this.translateService.instant('alerts.signup_error_3'));
|
this.alertService.presentToast(this.translateService.instant('alerts.signup_error_3'));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { name, email, phone, password, password1 } = form.value;
|
||||||
|
|
||||||
|
if (!name || !email || !phone || !password || !password1) {
|
||||||
|
this.alertService.presentToast(this.translateService.instant('alerts.signup_error_2'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (password !== password1) {
|
||||||
|
this.alertService.presentToast(this.translateService.instant('alerts.signup_error_1'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.loading = await this.loadingCtrl.create();
|
||||||
|
await this.loading.present();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Firebase crea la cuenta con email + password
|
||||||
|
const idToken = await this.firebaseAuthService.registerWithEmail(email, password);
|
||||||
|
|
||||||
|
// Backend crea el perfil y devuelve el token de la app
|
||||||
|
this.authService.registerWithFirebase(idToken, name, phone, email).subscribe(
|
||||||
|
(data: any) => {},
|
||||||
|
(error: any) => {
|
||||||
|
if (this.loading) this.loading.dismiss();
|
||||||
|
if (error['status'] === 422) {
|
||||||
|
this.alertService.presentToast(this.translateService.instant('alerts.signup_error'));
|
||||||
|
} else {
|
||||||
|
this.alertService.presentToast(this.translateService.instant('alerts.error') + error['message']);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
if (this.loading) this.loading.dismiss();
|
||||||
|
this.alertService.presentToast(this.translateService.instant('alerts.signup'));
|
||||||
|
this.navCtrl.navigateRoot('/dashboard');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} catch (e: any) {
|
||||||
|
if (this.loading) this.loading.dismiss();
|
||||||
|
if (e.code === 'auth/email-already-in-use') {
|
||||||
|
this.alertService.presentToast(this.translateService.instant('alerts.signup_error'));
|
||||||
|
} else {
|
||||||
|
this.alertService.presentToast(this.translateService.instant('alerts.error') + e.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async openTerms() {
|
async openTerms() {
|
||||||
|
|||||||
@@ -6,6 +6,10 @@ ion-footer {
|
|||||||
--ion-background-color: #175ccc;
|
--ion-background-color: #175ccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ion-footer ion-button::part(native) {
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
ion-header ion-toolbar {
|
ion-header ion-toolbar {
|
||||||
--min-height: 60px;
|
--min-height: 60px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
"login": "Log in",
|
"login": "Log in",
|
||||||
"signup": "Sign up",
|
"signup": "Sign up",
|
||||||
"forgot": "Forgot your password?",
|
"forgot": "Forgot your password?",
|
||||||
"fb_login": "Continue with Facebook",
|
"apple_login": "Continue with Apple",
|
||||||
"google_login": "Continue with Google",
|
"google_login": "Continue with Google",
|
||||||
"email": "Email",
|
"email": "Email",
|
||||||
"password": "Password",
|
"password": "Password",
|
||||||
@@ -142,7 +142,12 @@
|
|||||||
"keywords_hint": "Separate keywords with commas",
|
"keywords_hint": "Separate keywords with commas",
|
||||||
"address": "Address",
|
"address": "Address",
|
||||||
"discover": "How did you hear about us?",
|
"discover": "How did you hear about us?",
|
||||||
|
"select": "Select",
|
||||||
"discover_details": "Please specify how you found out about us",
|
"discover_details": "Please specify how you found out about us",
|
||||||
|
"bank": "Bank",
|
||||||
|
"bank_account": "Bank account",
|
||||||
|
"fee": "Minimum fee",
|
||||||
|
"required": "Field required",
|
||||||
"signup": "Sign up",
|
"signup": "Sign up",
|
||||||
"radio": "Radio",
|
"radio": "Radio",
|
||||||
"tv": "TV",
|
"tv": "TV",
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
"login": "Iniciar sesión",
|
"login": "Iniciar sesión",
|
||||||
"signup": "Registrate",
|
"signup": "Registrate",
|
||||||
"forgot": "¿Olvidó su contraseña?",
|
"forgot": "¿Olvidó su contraseña?",
|
||||||
"fb_login": "Iniciar sesión con Facebook",
|
"apple_login": "Iniciar sesión con Apple",
|
||||||
"google_login": "Iniciar sesión con Google",
|
"google_login": "Iniciar sesión con Google",
|
||||||
"email": "Correo electrónico",
|
"email": "Correo electrónico",
|
||||||
"password": "Contraseña",
|
"password": "Contraseña",
|
||||||
@@ -142,7 +142,12 @@
|
|||||||
"keywords_hint": "Separa las palabras clave con comas",
|
"keywords_hint": "Separa las palabras clave con comas",
|
||||||
"address": "Dirección",
|
"address": "Dirección",
|
||||||
"discover": "¿Cómo supiste de nosotros?",
|
"discover": "¿Cómo supiste de nosotros?",
|
||||||
|
"select": "Seleccionar",
|
||||||
"discover_details": "Específica como supiste de nosotros",
|
"discover_details": "Específica como supiste de nosotros",
|
||||||
|
"bank": "Banco",
|
||||||
|
"bank_account": "CLABE Interbancaria",
|
||||||
|
"fee": "Cuota mínima",
|
||||||
|
"required": "Campo requerido",
|
||||||
"signup": "Registrarse",
|
"signup": "Registrarse",
|
||||||
"radio": "Radio",
|
"radio": "Radio",
|
||||||
"tv": "TV",
|
"tv": "TV",
|
||||||
|
|||||||
Reference in New Issue
Block a user