In questa parte della nostra guida ci concentreremo su come completare l'integrazione di PayPal e Stripe nella nostra applicazione Angular. Abbiamo già configurato i componenti necessari per gestire i pagamenti. Ora ci occuperemo di come gestire gli eventi di pagamento, inviare i dati al server, gestire le risposte delle API e aggiornare l'interfaccia utente in base allo stato delle transazioni. Utilizzeremo l'applicazione già creata che include i componenti PayPalPaymentComponent
e StripePaymentComponent
.
Gestione degli eventi di pagamento
La gestione degli eventi di pagamento è cruciale per monitorare l'intero processo di transazione. I due principali sistemi di pagamento che stiamo utilizzando, PayPal e Stripe, forniscono eventi che possiamo catturare e gestire. Questo ci permette non solo di informare gli utenti riguardo allo stato delle loro transazioni. Consente anche di eseguire operazioni come l'aggiornamento dei dati nel database.
Nei componenti PayPalPaymentComponent
e StripePaymentComponent
abbiamo già impostato i metodi per iniziare il processo di pagamento. Ora dobbiamo aggiungere la logica per gestire il successo o il fallimento delle transazioni.
Aggiornamento di PayPalPaymentComponent
Aggiungiamo il metodo per inviare i dati del pagamento al server nel nostro PayPalPaymentComponent
. Dopo che l'ordine è stato catturato invieremo i dettagli della transazione ad un endpoint del nostro server.
import { Component, OnInit } from '@angular/core';
import { environment } from '../../environments/environments';
import { CommonModule } from '@angular/common';
import { RouterOutlet } from '@angular/router';
import { HttpClient } from '@angular/common/http'; // Rimuovi l'importazione di HttpClientModule
import { tap, catchError } from 'rxjs/operators';
import { of } from 'rxjs'; // Importa 'of' per gestire gli errori
@Component({
selector: 'app-paypal-payment',
templateUrl: './pay-pal-payment-component.component.html',
styleUrls: ['./pay-pal-payment-component.component.css'],
imports: [CommonModule, RouterOutlet], // Rimuovi HttpClientModule
standalone: true,
})
export class PayPalPaymentComponent implements OnInit {
constructor(private http: HttpClient) {}
onApprove(data: any, actions: any) {
return actions.order.capture().then((details: any) => {
alert('Transaction completed by ' + details.payer.name.given_name);
this.sendPaymentDetails(details);
});
}
sendPaymentDetails(paymentDetails: any) {
this.http.post('https://your-server.com/api/payments', paymentDetails).pipe(
tap(response => {
console.log('Payment details sent to the server:', response);
}),
catchError(error => {
console.error('Error sending payment details:', error);
return of(null); // Restituisce un valore alternativo in caso di errore
})
).subscribe(); // La sottoscrizione avviene, ma senza callback espliciti
}
ngOnInit(): void {
this.loadPayPalScript(); // Carica lo script di PayPal all'inizio
}
loadPayPalScript(): void {
if (!window.document.getElementById('paypal-script')) {
const script = window.document.createElement('script');
script.id = 'paypal-script';
script.src = `https://www.paypal.com/sdk/js?client-id=${environment.paypalClientId}¤cy=USD`;
script.onload = () => {
console.log('PayPal script loaded');
this.renderPayPalButton();
};
script.onerror = () => {
console.error('Error loading PayPal script');
};
window.document.body.appendChild(script);
} else {
this.renderPayPalButton(); // Chiamalo anche se lo script è già caricato
}
}
renderPayPalButton(): void {
console.log('Window.paypal:', window.paypal); // Log per verificare l'oggetto
if (window.paypal) {
window.paypal.Buttons({
createOrder: (data: any, actions: any) => {
return actions.order.create({
purchase_units: [{
amount: { value: '25.00' }
}]
});
},
onApprove: (data: any, actions: any) => {
return actions.order.capture().then((details: any) => {
alert('Transaction completed by ' + details.payer.name.given_name);
});
}
}).render('#paypal-button-container');
} else {
console.error('PayPal SDK not loaded');
}
}
}
Implementazione nei metodi di StripePaymentComponent
Analogamente, nel StripePaymentComponent
dobbiamo gestire il pagamento e inviare i dati al server. Aggiungiamo la logica nel metodo makePayment
:
import { Component, OnInit } from '@angular/core';
import { environment } from '../../environments/environments';
import { CommonModule } from '@angular/common';
import { RouterOutlet } from '@angular/router';
import { HttpClient } from '@angular/common/http'; // Mantieni HttpClient
import { tap, catchError } from 'rxjs/operators';
import { of } from 'rxjs'; // Importa 'of' per la gestione degli errori
@Component({
selector: 'app-stripe-payment',
templateUrl: './stripe-payment-component.component.html',
styleUrls: ['./stripe-payment-component.component.css'],
imports: [CommonModule, RouterOutlet], // Rimuovi HttpClientModule
standalone: true,
})
export class StripePaymentComponent implements OnInit {
paymentHandler: any = null;
stripeAPIKey: string = environment.stripeKey; // Chiave pubblica di Stripe
constructor(private http: HttpClient) {}
ngOnInit(): void {
this.loadStripeScript(); // Carica lo script di Stripe all'inizio
}
makePayment(amount: number): void {
const paymentHandler = (window).StripeCheckout.configure({
key: this.stripeAPIKey,
locale: 'auto',
token: (stripeToken: any) => {
console.log(stripeToken);
this.sendStripePaymentDetails(stripeToken); // Invia il token al server
},
});
paymentHandler.open({
name: 'Esempio Applicazione Angular',
description: 'Pagamenti con Stripe',
amount: amount * 100, // Importo in centesimi
});
}
sendStripePaymentDetails(token: any) {
this.http.post('https://your-server.com/api/stripe-payments', token).pipe(
tap(response => {
console.log('Stripe payment details sent to the server:', response);
}),
catchError(error => {
console.error('Error sending Stripe payment details:', error);
return of(null); // Restituisce un valore nullo in caso di errore
})
).subscribe(); // Sottoscrivi senza callback, gestione nel pipe
}
loadStripeScript(): void {
if (!window.document.getElementById('stripe-script')) {
const script = window.document.createElement('script');
script.id = 'stripe-script';
script.src = 'https://checkout.stripe.com/checkout.js';
window.document.body.appendChild(script);
}
}
}
Gestione delle Risposte delle API
Dopo aver inviato i dettagli del pagamento al server, possiamo gestire la risposta per confermare all'utente che la transazione è stata completata con successo. Utilizzeremo l'oggetto di risposta per fornire un feedback più dettagliato.
Aggiornamento dell'Interfaccia Utente
Modifichiamo i componenti per riflettere lo stato del pagamento. Creiamo una variabile paymentStatus
e aggiorniamo l'interfaccia utente di conseguenza.
sendPaymentDetails(paymentDetails: any) {
this.http.post('https://your-server.com/api/payments', paymentDetails).pipe(
tap(response => {
this.paymentStatus = 'success';
console.log('Payment details sent to the server:', response);
}),
catchError(error => {
this.paymentStatus = 'error';
console.error('Error sending payment details:', error);
return of(null); // Restituisce un valore alternativo in caso di errore
})
).subscribe(); // La sottoscrizione avviene, ma senza callback espliciti
}
Nel template HTML possiamo mostrare un messaggio diverso in base allo stato del pagamento:
<div class="container mt-5">
<h2 class="text-center">Paga con PayPal</h2>
<div id="paypal-button-container" class="mt-4"></div>
<div *ngIf="paymentStatus === 'success'" class="alert alert-success">
Pagamento completato con successo!
</div>
<div *ngIf="paymentStatus === 'error'" class="alert alert-danger">
Si è verificato un errore durante il pagamento. Riprova.
</div>
</div>
Facciamo lo stesso in StripePaymentComponent
:
paymentStatus: string = ''; //aggiungi la variabile
ngOnInit(): void {
this.loadStripeScript(); // Carica lo script di Stripe all'inizio
}
makePayment(amount: number): void {
const paymentHandler = (window).StripeCheckout.configure({
key: this.stripeAPIKey,
locale: 'auto',
token: (stripeToken: any) => {
console.log(stripeToken);
this.sendStripePaymentDetails(stripeToken); // Invia il token al server
},
});
paymentHandler.open({
name: 'Esempio Applicazione Angular',
description: 'Pagamenti con Stripe',
amount: amount * 100, // Importo in centesimi
});
}
sendStripePaymentDetails(token: any) {
this.http.post('https://your-server.com/api/stripe-payments', token).pipe(
tap(response => {
this.paymentStatus = 'success';
console.log('Stripe payment details sent to the server:', response);
}),
catchError(error => {
this.paymentStatus = 'error';
console.error('Error sending Stripe payment details:', error);
return of(null); // Restituisce un valore nullo in caso di errore
})
).subscribe(); // Sottoscrivi senza callback, gestione nel pipe
}
Aggiorniamo di conseguenza il template:
<div class="container mt-5">
<h2 class="text-center">Paga con Stripe</h2>
<div class="text-center mt-4">
<button class="btn btn-dark" (click)="makePayment(25)">Stripe</button>
</div>
<div *ngIf="paymentStatus === 'success'" class="alert alert-success">
Pagamento completato con successo!
</div>
<div *ngIf="paymentStatus === 'error'" class="alert alert-danger">
Si è verificato un errore durante il pagamento. Riprova.
</div>
</div>
Esecuzione del test
Ora esegui un test di pagamento con stripe. Ad esempio:
Come si può notare stiamo ottenendo un risposta di errore, quindi apriamo la console ed indaghiamo:
L'errore che stiamo riscontrando è legato alla politica CORS (Cross-Origin Resource Sharing). Questo significa che il browser sta bloccando la richiesta perché il server a cui stai tentando di accedere non consente richieste da altre origini (in questo caso, da http://localhost:4200
).
Possibili soluzioni
Una soluzione potrebbe essere quella di utilizzare un Proxy Angular
. Puoi configurare Angular per usare un proxy durante lo sviluppo, quindi crea un file proxy.conf.json
nella root principale del progetto con il seguente contenuto:
{
"/api": {
"target": "http://localhost:4200",
"secure": true,
"changeOrigin": true,
"logLevel": "debug"
}
}
Poi modifica il comando di avvio in package.json
per includere il proxy:
"scripts": {
"start": "ng serve --proxy-config proxy.conf.json"
}
In questo modo, tutte le richieste ad /api
verranno instradate attraverso il tuo server di sviluppo, evitando i problemi CORS che sono da scongiurare in produzione.
Creare un Backend temporaneo
Un'altra soluzione potrebbe essere quella di creare un Backend temporaneo, ad esempio con Node.js
ed Express
per gestire le chiamate a Stripe. Prima di tutto dovresti installare Express:
npm install express cors body-parser
Ed ecco l'esempio di un possibile server:
const express = require('express');
const cors = require('cors');
const bodyParser = require('body-parser');
const app = express();
app.use(cors());
app.use(bodyParser.json());
app.post('/api/stripe-payments', (req, res) => {
// Invia i dettagli a Stripe qui
res.send({ status: 'success' }); // Risposta di esempio
});
app.listen(3000, () => {
console.log('Server in ascolto sulla porta 3000');
});
Dopo aver avviato questo server dovremmo modificare il codice Angular per inviare richieste a http://localhost:3000/api/stripe-payments
.
Conclusione
In questo articolo abbiamo integrato i pagamenti di PayPal e Stripe nella nostra applicazione Angular. Avendo già configurato i componenti PayPalPaymentComponent
e StripePaymentComponent
abbiamo aggiunto logiche per gestire gli eventi di pagamento e aggiornare l'interfaccia utente in base allo stato delle transazioni.
Siamo poi passati alla gestione de gli eventi di pagamento con Angular, catturando il successo o il fallimento delle transazioni e aggiornando l'interfaccia utente di conseguenza. Inoltre, è stato affrontato il problema delle risposte delle API. Gestendo gli stati di successo ed errore in modo che gli utenti potessero ricevere un feedback chiaro.
Infine, si è discusso delle problematiche relative al CORS e delle possibili soluzioni. Come l'uso di un proxy Angular o la creazione di un semplice backend con Node.js ed Express. Queste soluzioni ci permettono di testare efficacemente l'integrazione dei pagamenti e di preparare il nostro progetto per la produzione.