richnologies / ngx-stripe

Angular 6+ wrapper for StripeJS
MIT License
221 stars 75 forks source link

[BUG] - mobile browser payments are failing #175

Closed shaiksarpa closed 1 year ago

shaiksarpa commented 2 years ago

I have integrated ngx-stripe to accept the payments from our platform which is built using Angular 9.

checkout page is working perfectly fine in desktop version without any issue, exactly same page if we try to access through mobile browser it fails when calling createToken API with the following error code.

{ "error": { "code": "incomplete_number", "type": "validation_error", "message": "Your card number is incomplete." } }

pespiritu25 commented 2 years ago

Seems to be working fine on my end. tho i am in test mode; not sure if that changes anything.

im using

Angular: "~12.2.0", stripe/stripe-js": "^1.32.0", "ngx-stripe": "^12.7.2",

Since you're using a deprecated version of angular, it could be part of the problem? https://angular.io/guide/releases#support-policy-and-schedule

atoyansk commented 2 years ago

I have the same issue here, using Angular 8. And it is quite counterproductive to upgrade an entire system because of one component.

richnologies commented 2 years ago

Hi @atoyansk and @shaiksarpa, in order to be able to help you I need some context:

What are your versions for Angular, ngx-stripe and @stirpe/stripe-js like @pespiritu25 has shared.

Also some info about what UI libraries are you using and a code sample of your component code so I can replicate

Thanks in advance

atoyansk commented 2 years ago

Hi @richnologies, the versions and UI library are:

Angular: "~8.2.3", "stripe/stripe-js": "^1.20.3", "ngx-stripe": "^8.2.0", "@angular/material": "^8.2.3", // using Material Design

Code Sample:

checkout.html <ngx-stripe-card [options]="cardOptions" [elementsOptions]="elementsOptions"></ngx-stripe-card>

checkout.ts

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

  @ViewChild(StripeCardComponent, {static: false}) card: StripeCardComponent;

  stripe = Stripe(apikey);
  elements = this.stripe.elements();

  appearance = {
    theme: 'stripe'
  };

  cardOptions: StripeCardElementOptions = {
    style: {
      base: {
        iconColor: '#888',
        color: '#000',
        fontWeight: '300',
        fontFamily: '"Rubik", Helvetica, sans-serif',
        fontSize: '16px',
        '::placeholder': {
          color: '#888'
        }
      }
    }
  };
  elementsOptions: StripeElementsOptions = {
    locale: 'he'
  };

If you need more information, let me know. Many thanks!

atoyansk commented 2 years ago

Hi @richnologies I have updated my Angular and ngx-stripe for the follow:

Angular: "^14.0.0" "stripe/stripe-js": "^1.38.1", "ngx-stripe": "^14.1.0", "@angular/material": "^14.0.0", // using Material Design

But the error in mobile remains the same:

{
    "error": {
        "code": "incomplete_number",
        "type": "validation_error",
        "message": "Your card number is incomplete."
    }
}

Considering the same code sample I sent before, is there anything I can do to avoid this error?

atoyansk commented 2 years ago

@richnologies any news about this?

richnologies commented 1 year ago

@atoyansk help me figure it out what this problem was related too.

At least in his case it was related to have two instances of the payment element in the same page, something like this:

<div class="hideIfmobile">
  <ng-container *ngIf="elementsOptions?.clientSecret">
    <ngx-stripe-payment
      [appearance]="appearance"
      [clientSecret]="elementsOptions?.clientSecret"
    ></ngx-stripe-payment>
  </ng-container>
</div>
<div class="showIfmobile">
  <ng-container *ngIf="elementsOptions?.clientSecret">
    <ngx-stripe-payment 
      [appearance]="appearance"
      [clientSecret]="elementsOptions?.clientSecret"
    ></ngx-stripe-payment>
  </ng-container>
</div>
@ViewChild(StripePaymentElementComponent) paymentElement: StripePaymentElementComponent;

In this case the paymentElement variable will always point to the first one, so when you're in mobile, it tries to access the desktop instance which is empty.

If you really want to have two instances, you can you plain old Template Refs:

<div class="hideIfmobile">
  <ng-container *ngIf="elementsOptions?.clientSecret">
    <ngx-stripe-payment #desktopPaymentElement
      [appearance]="appearance"
      [clientSecret]="elementsOptions?.clientSecret"
    ></ngx-stripe-payment>
  </ng-container>
</div>
<div class="showIfmobile">
  <ng-container *ngIf="elementsOptions?.clientSecret">
    <ngx-stripe-payment #mobilePaymentElement
      [appearance]="appearance"
      [clientSecret]="elementsOptions?.clientSecret"
    ></ngx-stripe-payment>
  </ng-container>
</div>
@ViewChild('desktopPaymentElement') desktopPaymentElement: StripePaymentElementComponent;
@ViewChild('mobilePaymentElement') mobilePaymentElement: StripePaymentElementComponent;

Now you can access the one you need and it should work fine.

Hope this helps!

Kind regards,

R