Skip to content
This repository has been archived by the owner on Jan 10, 2025. It is now read-only.

Scan pay front #3532

Open
wants to merge 91 commits into
base: master-qa
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
91 commits
Select commit Hold shift + click to select a range
5e6c81d
first shot - we can see a new ui
cabch Oct 6, 2022
d05f813
Merge remote-tracking branch 'origin/master-qa' into scan-pay-front
Oct 14, 2022
e482961
UIs for scan and pay
Oct 19, 2022
e15618b
remove unwanted changes
Oct 19, 2022
a5d398b
Change card title
Oct 25, 2022
0f3233f
send email with verify button
cabch Nov 10, 2022
553ec3a
reorganised folders
cabch Nov 10, 2022
65c6e99
Merge remote-tracking branch 'origin/master-qa' into scan-pay-front
Nov 14, 2022
f85b9ed
use payment intent
Nov 14, 2022
0b57511
Merge branch 'master-qa' into scan-pay-front
cabch Nov 14, 2022
06850c3
scan pay email working
cabch Nov 16, 2022
8d175d7
Merge branch 'master-qa' into scan-pay-front
cabch Nov 16, 2022
8244462
deleted old paymentintent in create payment method
cabch Nov 16, 2022
81592f4
new stripe element
Nov 16, 2022
f00bf32
confirm payment intent
cabch Nov 17, 2022
4574b30
- Stripe now handle the condition displaying - no more checkbox
cabch Nov 21, 2022
9d4b9e7
cleaned capture -> retriieve
cabch Nov 22, 2022
ac0a02f
Always pass chargingStationID and connectorID to the server
Nov 23, 2022
c3a9f56
added external
cabch Nov 24, 2022
730362e
first try on stop transaction
cabch Dec 2, 2022
9a4cb74
Merge branch 'scan-pay-front-NEPASPUSH' into scan-pay-front
cabch Dec 5, 2022
9273f67
Merge branch 'master-qa' into scan-pay-front
cabch Dec 13, 2022
a5a8d12
Merge branch 'master-qa' into scan-pay-front
cabch Jan 4, 2023
175c3a7
Merge remote-tracking branch 'origin/master-qa' into scan-pay-front
Jan 9, 2023
e7bab30
Add eula to user scan and pay
Jan 9, 2023
730f282
Merge remote-tracking branch 'origin/master-qa' into scan-pay-front
Jan 10, 2023
1cda70e
Customize error message of payment element
Jan 10, 2023
0cf2408
Show spinner before reCaptcha
Jan 10, 2023
71de482
Customize error message of payment element
Jan 10, 2023
4a14c98
Merge remote-tracking branch 'origin/master-qa' into scan-pay-front
Jan 11, 2023
9569d66
email sent message payment intent
Jan 11, 2023
5d28eda
put the appAutofocus on the email field
Jan 12, 2023
c54b551
flag the sendClicked on the response
Jan 12, 2023
9df5423
Hash user data scan pay
Jan 13, 2023
f87951c
added /stop transaction with transaction details + stop button working
cabch Jan 16, 2023
e73c05c
Revert "Hash user data scan pay"
cabch Jan 17, 2023
b1d58ac
stop transaction scan pay button disabled
cabch Jan 17, 2023
50bc222
show transaction scan-pay beta
Jan 17, 2023
9c97c18
transaction ??
cabch Jan 18, 2023
48b37ad
verification token in email url
cabch Jan 26, 2023
f4fb4b0
added verification token to retrie pi
cabch Jan 30, 2023
b01f370
tried to handle stop transaction WIP
cabch Feb 1, 2023
1a1890e
authticate external user
Feb 9, 2023
a3eef15
Secure get stripe facade
Feb 15, 2023
7b9bc9a
secure endpoints scan pay
Feb 20, 2023
613c900
secure scan pay endpoints
Feb 22, 2023
64e0bc5
logged user for show transaction
cabch Feb 22, 2023
04d95fd
replaced scanPayHandlePaymentIntentSetup
cabch Mar 7, 2023
7c87946
Merge branch 'master-qa' into scan-pay-front
cabch Mar 7, 2023
1480ae4
re added missed merge params
cabch Mar 7, 2023
ed4a2fa
never let the external user login into the app
Mar 8, 2023
fcddec3
handle no valid token
Mar 8, 2023
55fe5dd
invoice download + i18n alignement
cabch Mar 9, 2023
409ca78
handled error message when CS not connected from server
cabch Mar 9, 2023
23e8327
error messages clear for payment intent succeeded / failed
cabch Mar 13, 2023
df4d3b5
+ reorganized files
cabch Mar 15, 2023
55409ff
changed buttons
cabch Mar 15, 2023
3c8f112
Merge branch 'master-qa' into scan-pay-front
cabch Mar 15, 2023
3d83444
Merge remote-tracking branch 'origin/master-qa' into scan-pay-front
Mar 20, 2023
0619ee7
added scan pay component
cabch Mar 20, 2023
d15b8a5
Display qr code for scan and pay
Mar 21, 2023
833b3ab
settings scan pay hold amount in nilling settings
cabch Mar 21, 2023
54a1948
Download qr code for scan pay
Mar 21, 2023
926e255
Merge remote-tracking branch 'origin/master-qa' into scan-pay-front
Mar 28, 2023
76bba13
hide payment button when clicked
Mar 28, 2023
ee6258b
split scan pay setting to new component
cabch Mar 30, 2023
76ac03b
check connector availabality
Apr 3, 2023
3f94835
Merge branch 'master-qa' into scan-pay-front
cabch Apr 4, 2023
a5c2b63
disable button payement after click
Apr 4, 2023
d8e578a
Merge remote-tracking branch 'origin/master-qa' into scan-pay-front
Apr 12, 2023
ba78c95
new error handling with title + message + headerClass
cabch Apr 12, 2023
57b69f9
refactored scanpay dialog qr code generation
cabch Apr 13, 2023
55cc4a4
BL added
cabch Apr 13, 2023
851d81d
imports with relative path
cabch Apr 13, 2023
d803d9d
BL
cabch Apr 13, 2023
f3fab72
uncorrected italian
cabch Apr 13, 2023
e15fbea
BL added again
cabch Apr 13, 2023
a63dbb7
fixed show error message at stripe card step
cabch Apr 13, 2023
24475b9
modified stripe page to avoid "unexplained" error as payment element …
cabch Apr 13, 2023
b373c7e
aligned i18n
cabch Apr 14, 2023
5f4721e
hide button when error from stripe
cabch Apr 14, 2023
4a26759
forgot to send locale
cabch Apr 18, 2023
ff6a137
forgot one error message modif to fit i18n
cabch Apr 18, 2023
b587c78
handle locale from browser correctly
cabch Apr 19, 2023
4c7a1bd
Merge branch 'master-qa' into scan-pay-front
cabch Apr 19, 2023
eadfedd
fixed useless siteAreaID
cabch Apr 21, 2023
bf1d086
Merge branch 'master-qa' into scan-pay-front
cabch Apr 21, 2023
3f1654c
review part 1
Apr 21, 2023
e273bb8
fixed params.param with '?' in case params is null
cabch Apr 21, 2023
bd07d91
fixed error message not displaying
cabch Apr 24, 2023
258e068
added prepaiement message
cabch Apr 27, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion src/app/authentication/authentication.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router';
import { TranslateModule } from '@ngx-translate/core';
import { ScanPayEmailComponent } from 'authentication/scan-pay/email/scan-pay-email.component';
import { ComponentModule } from 'shared/component/component.module';
import { FormattersModule } from 'shared/formatters/formatters.module';

import { MaterialModule } from '../app.module';
import { DialogsModule } from '../shared/dialogs/dialogs.module';
Expand All @@ -15,6 +18,10 @@ import { AuthenticationLoginComponent } from './login/authentication-login.compo
import { AuthenticationMercedesDataUsageComponent } from './mercedes-data-usage/authentication-mercedes-data-usage.component';
import { AuthenticationRegisterComponent } from './register/authentication-register.component';
import { AuthenticationResetPasswordComponent } from './reset-password/authentication-reset-password.component';
import { ScanPayInvoiceComponent } from './scan-pay/invoices/scan-pay-invoice.component';
import { ScanPayComponent } from './scan-pay/scan-pay.component';
import { ScanPayShowTransactionComponent } from './scan-pay/show-transaction/scan-pay-show-transaction.component';
import { ScanPayStripePaymentIntentComponent } from './scan-pay/stripe/scan-pay-stripe-payment-intent.component';
import { AuthenticationVerifyEmailComponent } from './verify-email/authentication-verify-email.component';

@NgModule({
Expand All @@ -27,6 +34,8 @@ import { AuthenticationVerifyEmailComponent } from './verify-email/authenticatio
TranslateModule,
DialogsModule,
CommonDirectivesModule,
ComponentModule,
FormattersModule,
],
declarations: [
AuthenticationLoginComponent,
Expand All @@ -36,7 +45,12 @@ import { AuthenticationVerifyEmailComponent } from './verify-email/authenticatio
AuthenticationResetPasswordComponent,
AuthenticationDefinePasswordComponent,
AuthenticationVerifyEmailComponent,
AccountOnboardingComponent
AccountOnboardingComponent,
ScanPayStripePaymentIntentComponent,
ScanPayEmailComponent,
ScanPayShowTransactionComponent,
ScanPayComponent,
ScanPayInvoiceComponent,
],
})

Expand Down
27 changes: 26 additions & 1 deletion src/app/authentication/authentication.routing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ import { AuthenticationLoginComponent } from './login/authentication-login.compo
import { AuthenticationMercedesDataUsageComponent } from './mercedes-data-usage/authentication-mercedes-data-usage.component';
import { AuthenticationRegisterComponent } from './register/authentication-register.component';
import { AuthenticationResetPasswordComponent } from './reset-password/authentication-reset-password.component';
import { ScanPayEmailComponent } from './scan-pay/email/scan-pay-email.component';
import { ScanPayInvoiceComponent } from './scan-pay/invoices/scan-pay-invoice.component';
import { ScanPayShowTransactionComponent } from './scan-pay/show-transaction/scan-pay-show-transaction.component';
import { ScanPayStripePaymentIntentComponent } from './scan-pay/stripe/scan-pay-stripe-payment-intent.component';
import { AuthenticationVerifyEmailComponent } from './verify-email/authentication-verify-email.component';

export const AuthenticationRoutes: Routes = [
Expand Down Expand Up @@ -37,7 +41,28 @@ export const AuthenticationRoutes: Routes = [
{
path: 'account-onboarding',
component: AccountOnboardingComponent,
}, {
},
// Step #1 - flash QR code
{
path: 'scan-pay/:chargingStationID/:connectorID',
component: ScanPayEmailComponent,
},
// Step #2 - click on the link from the email
{
path: 'scan-pay',
component: ScanPayStripePaymentIntentComponent,
},
// Step #3 - show and can stop transaction
{
path: 'scan-pay/stop/:transactionID/:email/:token',
component: ScanPayShowTransactionComponent,
},
// Step #4 - download invoice from email once transaction is billed
{
path: 'scan-pay/invoice/:invoiceID/download',
component: ScanPayInvoiceComponent
},
{
path: '**',
redirectTo: 'login',
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<div class="wrapper wrapper-full-page">
<div class="page-header login-page header-filter" filter-color="black">
<div class="container">
<div class="col-lg-6 ms-auto me-auto">
<form class="form" [formGroup]="formGroup">
<div class="card card-login card-hidden">
<div class="card-header {{headerClass}} text-center h-25">
<div class="social-line">
<div style="height: 125px; display: contents; margin: 5px;">
<h4 class="mb2 card-title text-center" style="padding: 10px;">{{title | translate}}</h4>
</div>
</div>
</div>
<div class="card-body">
<h4 class="mb2 card-title text-center" style="padding: 10px;" *ngIf="isSendClicked">{{message | translate}}</h4>
<span *ngIf="!isSendClicked" class="bmd-form-group">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text">
<mat-icon>email</mat-icon>
<mat-form-field class="ms-2">
<input appAutofocus matInput type="text" placeholder="{{'authentication.email' | translate}}"
[formControl]="email">
<mat-error *ngIf="email.errors?.email">{{"authentication.invalid_email" | translate}}</mat-error>
<mat-error *ngIf="email.errors?.required">{{"general.mandatory_field" | translate}}</mat-error>
</mat-form-field>
</span>
</div>
<div class="input-group-prepend">
<span class="input-group-text">
<mat-icon>account_circle</mat-icon>
<mat-form-field class="ms-2">
<input id="last-name-field" matInput type="text" placeholder="{{'users.name' | translate}}"
[formControl]="name" (input)="toUpperCase(name)">
<mat-error *ngIf="name.errors?.required">{{"general.mandatory_field" | translate}}</mat-error>
</mat-form-field>
</span>
</div>
<div class="input-group-prepend input-group-no-icon">
<mat-form-field class="ms-2">
<input id="first-name-field" matInput type="text" placeholder="{{'users.first_name' | translate}}"
[formControl]="firstName" (input)="firstLetterToUpperCase(firstName)">
<mat-error *ngIf="firstName.errors?.required">{{"general.mandatory_field" | translate}}</mat-error>
</mat-form-field>
</div>
</div>
<div class="recaptcha-text">
{{"general.captcha_text_1" | translate}}
<a href="https://policies.google.com/privacy"
target="_blank">{{"general.captcha_text_2" | translate}}</a>{{"general.captcha_text_3" | translate}}
<a href="https://policies.google.com/terms"
target="_blank">{{"general.captcha_text_4" | translate}}</a>{{"general.captcha_text_5" | translate}}.
</div>
<div class="input-group-prepend text-center mt-3 ms-2">
<mat-checkbox [formControl]="acceptEula" required>
<span id="eula-checkbox" class="adapt-font-size">{{'authentication.accept' | translate}} </span>
<a class="auth-link" href="/auth/eula" target="_blank">
<span class="adapt-font-size">{{'authentication.eula' | translate}}</span>
</a>
</mat-checkbox>
</div>
</span>
</div>
<div class="card-footer justify-content-center mb-4" *ngIf="!isSendClicked">
<button mat-raised-button color="primary" (click)="sendEmailVerificationScanAndPay(formGroup.value)"
[disabled]="!formGroup.valid || isSendClicked">{{"settings.scan_pay.payment_intent.create_account_send_email" | translate}}
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
168 changes: 168 additions & 0 deletions src/app/authentication/scan-pay/email/scan-pay-email.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
import { AbstractControl, FormControl, UntypedFormGroup, Validators } from '@angular/forms';
import { ActivatedRoute, Params } from '@angular/router';
import { StatusCodes } from 'http-status-codes';
import { ReCaptchaV3Service } from 'ngx-captcha';

import { CentralServerService } from '../../../services/central-server.service';
import { ConfigService } from '../../../services/config.service';
import { LocaleService } from '../../../services/locale.service';
import { SpinnerService } from '../../../services/spinner.service';
import { WindowService } from '../../../services/window.service';
import { Constants } from '../../../utils/Constants';
import { Utils } from '../../../utils/Utils';

@Component({
selector: 'app-scan-pay-email',
templateUrl: 'scan-pay-email.component.html',
})

export class ScanPayEmailComponent implements OnInit, OnDestroy {
public email: AbstractControl;
public name: AbstractControl;
public firstName: AbstractControl;
public formGroup: UntypedFormGroup;
public isSendClicked: boolean;
public tenantLogo = Constants.NO_IMAGE;
public acceptEula: AbstractControl;
public headerClass = 'card-header-primary';
public title = 'settings.scan_pay.payment_intent.create_account_title';
public message: string;
public locale: string;

private siteKey: string;
private subDomain: string;
private params: Params;

public constructor(
private centralServerService: CentralServerService,
private spinnerService: SpinnerService,
private reCaptchaV3Service: ReCaptchaV3Service,
private windowService: WindowService,
private configService: ConfigService,
private activatedRoute: ActivatedRoute,
private localeService: LocaleService) {
this.localeService.getCurrentLocaleSubject().subscribe((locale) => {
this.locale = locale.currentLocaleJS;
});

// Get the Site Key
this.siteKey = this.configService.getUser().captchaSiteKey;
this.params = this.activatedRoute?.snapshot?.params;
// Init Form
this.formGroup = new UntypedFormGroup({
email: new FormControl(null,
Validators.compose([
Validators.required,
Validators.email,
])),
name: new FormControl(null,
Validators.compose([
Validators.required
])),
firstName: new FormControl(null,
Validators.compose([
Validators.required
])),
acceptEula: new FormControl(null,
Validators.compose([
Validators.required,
])),
});
// Keep the sub-domain
this.subDomain = this.windowService.getSubdomain();
// Form
this.email = this.formGroup.controls['email'];
this.name = this.formGroup.controls['name'];
this.firstName = this.formGroup.controls['firstName'];
this.acceptEula = this.formGroup.controls['acceptEula'];
setTimeout(() => {
const card = document.getElementsByClassName('card')[0];
// After 700 ms we add the class animated to the login/register card
card.classList.remove('card-hidden');
}, 700);
this.isSendClicked = false;
}

public ngOnInit() {
const body = document.getElementsByTagName('body')[0];
body.classList.add('lock-page');
body.classList.add('off-canvas-sidebar');
if (this.subDomain) {
// Retrieve tenant's logo
this.centralServerService.getTenantLogoBySubdomain(this.subDomain).subscribe({
next: (tenantLogo: string) => {
if (tenantLogo) {
this.tenantLogo = tenantLogo;
}
},
error: (error) => {
this.spinnerService.hide();
switch (error.status) {
case StatusCodes.NOT_FOUND:
this.tenantLogo = Constants.NO_IMAGE;
break;
default:
this.isSendClicked = true;
this.headerClass = 'card-header-danger';
this.title = 'settings.scan_pay.unexpected_error_title';
this.message = 'settings.scan_pay.unexpected_error_payment_intend';
}
}
});
} else {
this.tenantLogo = Constants.MASTER_TENANT_LOGO;
}
}

public ngOnDestroy() {
const body = document.getElementsByTagName('body')[0];
body.classList.remove('lock-page');
body.classList.remove('off-canvas-sidebar');
}

public toUpperCase(control: AbstractControl) {
control.setValue(control.value.toUpperCase());
}

public firstLetterToUpperCase(control: AbstractControl) {
if (control.value) {
control.setValue(Utils.firstLetterInUpperCase(control.value));
}
}

public sendEmailVerificationScanAndPay(data: any) {
// Show
this.spinnerService.show();
this.reCaptchaV3Service.execute(this.siteKey, 'VerifScanPay', (token) => {
if (token) {
data['captcha'] = token;
data['chargingStationID'] = this.params?.chargingStationID;
data['connectorID'] = this.params?.connectorID;
data['locale'] = this.locale;
} else {
this.headerClass = 'card-header-danger';
this.title = 'settings.scan_pay.unexpected_error_title';
this.message = 'settings.scan_pay.payment_intent.authentication.invalid_captcha_token';
return;
}
// launch email verif
this.centralServerService.scanPayVerifyEmail(data).subscribe({
next: (response) => {
this.isSendClicked = true;
this.spinnerService.hide();
this.headerClass = 'card-header-success';
this.title = 'settings.scan_pay.payment_intent.create_account_success_title';
this.message = 'settings.scan_pay.payment_intent.create_account_success';
},
error: (error) => {
this.isSendClicked = true;
this.spinnerService.hide();
this.headerClass = 'card-header-danger';
this.title = 'settings.scan_pay.unexpected_error_title';
this.message = 'settings.scan_pay.payment_intent.create_account_error';
}
});
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<div class="wrapper wrapper-full-page">
<div class="page-header login-page header-filter" filter-color="black">
<div class="container">
<div class="col-lg-6 ms-auto me-auto">
<div class="card card-login">
<div class="card-header {{headerClass}} text-center h-25">
<div class="social-line">
<div style="height: 125px; display: contents; margin: 5px;">
<h4 class="mb2 card-title text-center" style="padding: 10px;">{{title | translate}}</h4>
</div>
</div>
</div>
<div class="card-body" >
<div class="tab-content">
<h4 class="mb2 card-title text-center" style="padding: 10px;">{{message | translate}}</h4>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
Loading