Skip to content

Commit

Permalink
feat(components): add support for payment element
Browse files Browse the repository at this point in the history
  • Loading branch information
richnologies committed Oct 22, 2021
1 parent 96390b3 commit 611417e
Show file tree
Hide file tree
Showing 21 changed files with 769 additions and 42 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

## 12.7.0 - 2021-10-22

- Add support for Payment Element
- Add support for Affirm Payment
- Add support for Prompt Pay Payment
- Add support for Pay Now Payment

## 12.6.0 - 2021-10-10

- Add support for Loading Template
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,12 @@
"@angular/pwa": "^12.0.0",
"@angular/router": "^12.0.0",
"@angular/service-worker": "^12.0.0",
"@stripe/stripe-js": "^1.18.0",
"@stripe/stripe-js": "^1.20.3",
"core-js": "^2.5.4",
"ngx-build-modern": "^1.1.10",
"ngx-build-plus": "^12.0.1",
"rxjs": "~6.6.0",
"stripe": "^8.184.0",
"tslib": "^2.0.0",
"zone.js": "~0.11.4"
},
Expand Down
8 changes: 8 additions & 0 deletions projects/ngx-stripe-tester/src/app/app.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@
<mat-icon class="mat-18">assessment</mat-icon>
Test 04
</a>
<a mat-list-item routerLink="/test-05" routerLinkActive="active">
<mat-icon class="mat-18">assessment</mat-icon>
Test 05
</a>
<a mat-list-item routerLink="/test-06" routerLinkActive="active">
<mat-icon class="mat-18">assessment</mat-icon>
Test 06
</a>
<mat-divider></mat-divider>
</mat-nav-list>
</mat-sidenav>
Expand Down
16 changes: 13 additions & 3 deletions projects/ngx-stripe-tester/src/app/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import { BrowserModule } from '@angular/platform-browser';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { HttpClientModule } from '@angular/common/http';
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { ReactiveFormsModule } from '@angular/forms';
import { ServiceWorkerModule } from '@angular/service-worker';

import { NgxStripeModule } from 'ngx-stripe';

import { environment } from '../environments/environment';

import { SharedModule } from './shared/shared.module';
import { CoreModule } from './core/core.module';

import { CoreModule, PLUTO_ID } from './core';

import { AppComponent } from './app.component';
import { ROUTES } from './app.routing';
Expand All @@ -18,16 +21,23 @@ import { ROUTES } from './app.routing';
declarations: [AppComponent],
imports: [
BrowserModule,
HttpClientModule,
RouterModule.forRoot(ROUTES, { relativeLinkResolution: 'legacy' }),
NgxStripeModule.forRoot('pk_test_nDR7IWEIGLp4a1SBtqKH5eyg'),
NgxStripeModule.forRoot('pk_test_51Ii5RpH2XTJohkGafOSn3aoFFDjfCE4G9jmW48Byd8OS0u2707YHusT5PojHOwWAys9HbvNylw7qDk0KkMZomdG600TJYNYj20'),
ReactiveFormsModule,
NoopAnimationsModule,
ServiceWorkerModule.register('ngsw-worker.js', {
enabled: environment.production
}),
SharedModule,
CoreModule
],
providers: [],
providers: [
{
provide: PLUTO_ID,
useValue: '449f8516-791a-49ab-a09d-50f79a0678b6'
}
],
bootstrap: [AppComponent]
})
export class AppModule {}
8 changes: 8 additions & 0 deletions projects/ngx-stripe-tester/src/app/app.routing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ export const ROUTES: Routes = [
path: 'test-04',
loadChildren: () => import('./stripe-test-04/stripe-test-04.module').then(m => m.StripeTest04Module)
},
{
path: 'test-05',
loadChildren: () => import('./stripe-test-05/stripe-test-05.module').then(m => m.StripeTest05Module)
},
{
path: 'test-06',
loadChildren: () => import('./stripe-test-06/stripe-test-06.module').then(m => m.StripeTest06Module)
},
{
path: 'welcome',
loadChildren: () => import('./welcome/welcome.module').then(m => m.WelcomeModule)
Expand Down
4 changes: 4 additions & 0 deletions projects/ngx-stripe-tester/src/app/core/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export * from './pluto/client-id.provider';
export * from './pluto/pluto.service';

export * from './core.module';
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { InjectionToken } from '@angular/core';

export const PLUTO_ID = new InjectionToken<string>('[PLUTO] ClientID');
34 changes: 34 additions & 0 deletions projects/ngx-stripe-tester/src/app/core/pluto/pluto.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { HttpClient } from '@angular/common/http';
import { Inject, Injectable } from '@angular/core';
import { Observable } from 'rxjs';

import { PaymentIntent } from '@stripe/stripe-js';
import Stripe from 'stripe';

import { PLUTO_ID } from './client-id.provider';

@Injectable({ providedIn: 'root' })
export class PlutoService {
private static readonly BASE_URL = 'https://api.pluto.ricardosanchez.dev/api';

constructor(
@Inject(PLUTO_ID) private readonly clientId: string,
private readonly http: HttpClient
) {}

createPaymentIntent(params: Stripe.PaymentIntentCreateParams): Observable<PaymentIntent> {
return this.http.post<PaymentIntent>(
`${PlutoService.BASE_URL}/payments/create-payment-intent`,
params,
{ headers: { merchant: this.clientId } }
);
}

createVerificationSession(userid: string): Observable<any> {
return this.http.post<PaymentIntent>(
`${PlutoService.BASE_URL}/identity/create-verification-session`,
{ userid },
{ headers: { merchant: this.clientId } }
);
}
}
2 changes: 2 additions & 0 deletions projects/ngx-stripe-tester/src/app/shared/material.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { NgModule } from '@angular/core';

import { MatDividerModule } from '@angular/material/divider';
import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { MatListModule } from '@angular/material/list';
import { MatProgressBarModule } from '@angular/material/progress-bar';
import { MatSidenavModule } from '@angular/material/sidenav';
Expand All @@ -10,6 +11,7 @@ import { MatToolbarModule } from '@angular/material/toolbar';
const modules = [
MatDividerModule,
MatIconModule,
MatInputModule,
MatListModule,
MatProgressBarModule,
MatSidenavModule,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { Component, ViewChild } from '@angular/core';
import { FormBuilder, Validators } from '@angular/forms';
import { switchMap } from 'rxjs/operators';

import { StripeService, StripeCardComponent, StripeFactoryService } from 'ngx-stripe';
import {
StripeCardElementOptions,
StripeElementsOptions
} from '@stripe/stripe-js';

import { PlutoService } from '../core';

@Component({
selector: 'app-test-05',
template: `
<app-section maxWidth="900">
<mat-toolbar color="secondary" section-content-header>
<span>Card Payment Intent Example</span>
</mat-toolbar>
<div section-content [formGroup]="stripeTest">
<input placeholder="name" formControlName="name" />
<input placeholder="amount" type="number" formControlName="amount" />
<ngx-stripe-card [options]="cardOptions">
<span style="color: green" *ngxStripeLoadingTemplate>
Loading Stripe Card...
</span>
</ngx-stripe-card>
<button (click)="pay()">PAY</button>
</div>
</app-section>
`,
styles: []
})
export class Test05Component {
@ViewChild(StripeCardComponent) card: StripeCardComponent;

stripe = this.factory.create(
'pk_test_51IvkafL0RbPb0ITBwzybjdb6C24qabOLoPgyig6ZoPhhQDUpu0ghKJISVKVMwIarXnxI2r4LTJyPS3dMkdol1WS2007tHNTSok',
{ apiVersion: '2020-08-27' }
);

stripeTest = this.fb.group({
name: ['Angular v11', [Validators.required]],
amount: [1105, [Validators.required, Validators.pattern(/\d+/)]]
});

cardOptions: StripeCardElementOptions = {
style: {
base: {
iconColor: '#666EE8',
color: '#31325F',
fontWeight: '300',
fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
fontSize: '18px',
'::placeholder': {
color: '#CFD7E0'
}
}
}
};

elementsOptions: StripeElementsOptions = {
locale: 'en'
};

paying = false;

constructor(
private fb: FormBuilder,
private plutoService: PlutoService,
private factory: StripeFactoryService,
private stripeService: StripeService
) {}

pay() {
if (this.stripeTest.valid) {
this.paying = true;
this.plutoService
.createPaymentIntent({
amount: this.stripeTest.get('amount').value,
currency: 'eur'
})
.pipe(
switchMap(pi =>
this.stripeService.confirmCardPayment(pi.client_secret, {
payment_method: {
card: this.card.element,
billing_details: {
name: this.stripeTest.get('name').value
}
}
})
)
)
.subscribe(result => {
this.paying = false;
console.log('Result', result);
if (result.error) {
// Show error to your customer (e.g., insufficient funds)
alert({ success: false, error: result.error.message });
} else {
// The payment has been processed!
if (result.paymentIntent.status === 'succeeded') {
// Show a success message to your customer
alert({ success: true });
}
}
});
} else {
console.log(this.stripeTest);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { CommonModule } from '@angular/common';

import { NgxStripeModule } from 'ngx-stripe';

import { SharedModule } from '../shared/shared.module';
import { Test05Component } from './stripe-test-05.component';

const routes: Routes = [
{
path: '',
component: Test05Component
}
];

@NgModule({
declarations: [Test05Component],
imports: [
CommonModule,
NgxStripeModule,
RouterModule.forChild(routes),
SharedModule
]
})
export class StripeTest05Module {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { Component, OnInit, ViewChild } from '@angular/core';
import { FormBuilder, Validators } from '@angular/forms';

import { StripeService, StripePaymentElementComponent } from 'ngx-stripe';
import { StripeElementsOptions } from '@stripe/stripe-js';

import { PlutoService } from '../core';

@Component({
selector: 'app-test-06',
template: `
<app-section maxWidth="900">
<mat-toolbar color="secondary" section-content-header>
<span>Payment Element Test</span>
</mat-toolbar>
<div section-content [formGroup]="stripeTest">
<mat-form-field class="example-full-width" appearance="fill">
<input matInput placeholder="name" formControlName="name" />
</mat-form-field>
<mat-form-field class="example-full-width" appearance="fill">
<input matInput placeholder="amount" type="number" formControlName="amount" />
</mat-form-field>
<ngx-stripe-payment [clientSecret]="elementsOptions?.clientSecret"></ngx-stripe-payment>
<button (click)="pay()">PAY</button>
</div>
</app-section>
`,
styles: []
})
export class Test06Component implements OnInit {
@ViewChild(StripePaymentElementComponent) paymentElement: StripePaymentElementComponent;

stripeTest = this.fb.group({
name: ['Angular v12', [Validators.required]],
amount: [1109, [Validators.required, Validators.pattern(/\d+/)]]
});

elementsOptions: StripeElementsOptions = {
locale: 'en'
};

paying = false;

constructor(
private fb: FormBuilder,
private plutoService: PlutoService,
private stripeService: StripeService
) {}

ngOnInit() {
this.plutoService.createPaymentIntent({
amount: this.stripeTest.get('amount').value,
currency: 'eur'
}).subscribe(pi => {
this.elementsOptions.clientSecret = pi.client_secret;
});
}

pay() {
if (this.stripeTest.valid) {
this.paying = true;
this.stripeService.confirmPayment({
elements: this.paymentElement.elements,
confirmParams: {
payment_method_data: {
billing_details: {
name: this.stripeTest.get('name').value
}
}
},
redirect: 'if_required'
}).subscribe(result => {
this.paying = false;
console.log('Result', result);
if (result.error) {
// Show error to your customer (e.g., insufficient funds)
alert({ success: false, error: result.error.message });
} else {
// The payment has been processed!
if (result.paymentIntent.status === 'succeeded') {
// Show a success message to your customer
alert({ success: true });
}
}
});
} else {
console.log(this.stripeTest);
}
}
}
Loading

0 comments on commit 611417e

Please sign in to comment.