I followed a long tutorial, and built my application side by side using the design patterns from the turorial. I am now stuck, as I don't know how to implement paypal within the scheme I'm using. I used rxjs and observables to build the app, and admittedly I don't really understand them well. Sorry if this is vague, I don;t know what else to do. The paypal implementation is as follows...
This is the code I do not understand how to implement.
TS file
export class DeposittestComponent implements OnInit {
PAYPAL_CLIENT_ID: string = '##################';
myAmount: any
@ViewChild('paypalRef', { static: true }) private paypalRef!: ElementRef;
ngOnInit(): void {
this.renderPaypalButton();
}
renderPaypalButton() {
let orderRef: string | null = null;
loadScript({ "clientId": this.PAYPAL_CLIENT_ID, currency: 'USD' })
.then((loadedPaypal) => {
if (loadedPaypal) {
const paypal: PayPalNamespace = loadedPaypal;
paypal.Buttons({
style: {
layout: 'vertical',
color: 'blue',
shape: 'rect',
label: 'paypal',
},
createOrder: (data, actions) => {
const postData = {
amount: this.myAmount
};
return fetch(AppSettings.API_ENDPOINT + '/user/create_paypal_transaction', {
method: "post",
headers: {
'Accept': 'application/json, text/plain, */*',
'Content-Type': 'application/json'
},
body: JSON.stringify(postData)
})
.then((response) => response.json())
.then((response) => {
orderRef = response.orderRef;
return response.id;
});
},
onApprove: (data, actions) => {
return fetch(AppSettings.API_ENDPOINT + `/user/orders/${data.orderID}/capture`, {
method: "post",
headers: {
'Accept': 'application/json, text/plain, */*',
'Content-Type': 'application/json',
},
})
.then((response) => response.json())
.then((orderData) => {
const errorDetail = Array.isArray(orderData.details) && orderData.details[0];
if (errorDetail && errorDetail.issue === 'INSTRUMENT_DECLINED') {
return actions.restart();
}
const transaction = orderData.purchase_units[0].payments.captures[0];
this.paypalRedirect(transaction.status, orderRef);
});
},
onCancel: () => {
//
},
onError: (err) => {
this.paypalRedirect('ERROR', orderRef);
}
}).render(this.paypalRef.nativeElement);
} else {
console.error("");
}
})
.catch((error) => {
console.error("", error);
});
}
paypalRedirect(status: string, orderRef: string | null) {
switch (status) {
case 'COMPLETED':
if (orderRef) {
//this.router.navigate(\['/result/success/' + orderRef\]);
} else {
console.error("");
}
break;
case 'ERROR':
if (orderRef) {
//this.router.navigate(\['/result/error/' + orderRef\]);
} else {
console.error("");
}
break;
default:
console.error("");
break;
}
}
HTML
<div class="form-group">
<label>Amount</label>
<input type="text" ngModel name="myAmount" (ngModelChange)="myAmount=$event"
value="$" class="form-control">
</div>
<div #paypalRef></div>
This is the design pattern of everything else I have done in the application.
TS
export class NewGameAccountComponent implements OnInit {
newGameAccountState$: Observable<State<CustomHttpResponse<any>>>;
private dataSubject = new BehaviorSubject<CustomHttpResponse<any>>(null);
private isLoadingSubject = new BehaviorSubject<boolean>(false);
isLoading$ = this.isLoadingSubject.asObservable();
readonly DataState = DataState;
constructor(private gameAccountsService: GameAccountsService) { }
ngOnInit(): void {
this.newGameAccountState$ = this.gameAccountsService.activeGameAccounts$()
.pipe(
map(response => {
console.log(response);
this.dataSubject.next(response);
return { dataState: DataState.LOADED, appData: response };
}),
startWith({ dataState: DataState.LOADING }),
catchError((error: string) => {
return of({ dataState: DataState.ERROR, error })
})
)
}
createNewGameAccount(newGameAccountForm: NgForm): void {
this.isLoadingSubject.next(true);
this.newGameAccountState$ = this.gameAccountsService.newGameAccount$(newGameAccountForm.value)
.pipe(
map(response => {
console.log(response);
newGameAccountForm.reset({});
this.isLoadingSubject.next(false);
return { dataState: DataState.LOADED, appData: this.dataSubject.value };
}),
startWith({ dataState: DataState.LOADED, appData: this.dataSubject.value }),
catchError((error: string) => {
this.isLoadingSubject.next(false);
return of({ dataState: DataState.LOADED, error })
})
)
}
}
HTML
<ng-container *ngIf="(newGameAccountState$ | async) as state" [ngSwitch]="state.dataState">
<ng-container *ngSwitchCase="DataState.LOADED">
<app-navbar [user]="state?.appData?.data?.user"></app-navbar>
<section>
<div class="container">
<div class="row justify-content-center">
<div class="col-md-12">
<div class="card">
<div class="card-body">
<div class="text-center">
<h2><i style="margin-right: 5px;" class="bi bi-person-plus-fill"></i> New Game
Account
</h2>
</div>
<form #newGameAccountForm="ngForm"
(ngSubmit)="createNewGameAccount(newGameAccountForm)">
///LOTS OF INPUTS FOR FORM
<button
[disabled]="state.dataState === DataState.LOADING || newGameAccountForm.invalid || newGameAccountForm.pristine|| (isLoading$ | async)"
type="submit" class="btn btn-primary mt-5">
<span *ngIf="isLoading$ | async" class="spinner-border spinner-border-sm"
role="status" aria-hidden="true" style="margin-right: 5px;"></span>
<span *ngIf="isLoading$ | async">Saving...</span>
<span *ngIf="!(isLoading$ | async)">Save Game Account</span>
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</section>
</ng-container>
</ng-container>
SERVICE
export class GameAccountsService {
private readonly server: string = AppSettings.API_ENDPOINT;
constructor(private http: HttpClient) { }
activeGameAccounts$ = () => <Observable<CustomHttpResponse<User & GameAccount>>>
this.http.get<CustomHttpResponse<User & GameAccount>>
(`${this.server}/user/game_accounts/list_active`)
.pipe(
tap(console.log),
catchError(this.handleError)
);
newGameAccount$ = (gameAccount: GameAccount) => <Observable<CustomHttpResponse<User & GameAccount>>>
this.http.post<CustomHttpResponse<User & GameAccount>>
(`${this.server}/user/game_account/create`, gameAccount)
.pipe(
tap(console.log),
catchError(this.handleError)
);
}
interceptor
@Injectable()
export class TokenInterceptor implements HttpInterceptor {
private isTokenRefreshing: boolean = false;
private refreshTokenSubject: BehaviorSubject<CustomHttpResponse<Profile>> = new BehaviorSubject(null);
constructor(private userService: UserService) {}
intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> | Observable<HttpResponse<unknown>>{
if(request.url.includes('verify') || request.url.includes('login') || request.url.includes('register')
|| request.url.includes('refresh') || request.url.includes('resetpassword')|| request.url.includes('reset_password')) {
return next.handle(request);
}
return next.handle(this.addAuthorizationTokenHeader(request, localStorage.getItem(Key.TOKEN)))
.pipe(
catchError((error: HttpErrorResponse) => {
if(error instanceof HttpErrorResponse && error.status === 401 && error.error.reason.includes('expired')) {
return this.handleRefreshToken(request, next);
} else {
return throwError(() => error);
}
})
);
}
Could someone please help me. Simple stuff like even getting the paypal button to load while using the pattern i used is eluding me. Thank you for reading