google-pay / flutter-plugin

Apache License 2.0
145 stars 129 forks source link

[BUG] Changing `paymentItem` on a button does not re-render the buttons logic. #234

Closed dickermoshe closed 11 months ago

dickermoshe commented 11 months ago

I've created a Widget that shows the correct button depending on the platform. There is a big problem. If the parent widget changes priceInCents, the widget DOES rebuild, however the original price is still saved in the Button.

This is for a donate page, the $18 option is selected by default. However if a user selects another amount and we call setState(), the button will still charge the original amount. This is a very significant bug!!!

import 'dart:io';

import 'package:app/src/common/services/donate/conts.dart';
import 'package:app/src/common/services/donate/stripe.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:pay/pay.dart' as p;

class AdaptivePaymentButton extends HookConsumerWidget {
  const AdaptivePaymentButton(
      {super.key,
      required this.priceInCents,
      this.onPressed,
      this.onSuccess,
      this.onError});
  final int priceInCents;
  final VoidCallback? onPressed;
  final VoidCallback? onSuccess;
  final void Function(Object?)? onError;

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    const height = 48.0;
    const width = 200.0;

    void onErrorWithCatchCancel(Object? error) {
      if (error is PlatformException) {
        if (error.code == "paymentCanceled") {
          return;
        }
      }
      if (onError != null) onError!(error);
    }

    final paymentItem = p.PaymentItem(
        label: "Donation",
        amount: (priceInCents / 100).toStringAsFixed(2),
        type: p.PaymentItemType.total,
        status: p.PaymentItemStatus.final_price);
    if (Platform.isIOS) {
      return p.ApplePayButton(
        height: height,
        width: width,
        onPressed: onPressed,
        paymentConfiguration:
            p.PaymentConfiguration.fromJsonString(defaultApplePay),
        onError: onErrorWithCatchCancel,
        type: p.ApplePayButtonType.donate,
        onPaymentResult: (result) {
          runApplePay(result, amountInCents: priceInCents);
          if (onSuccess != null) onSuccess!();
        },
        paymentItems: [paymentItem],
      );
    } else if (Platform.isAndroid) {
      return p.GooglePayButton(
          height: height,
          width: width,
          onError: onErrorWithCatchCancel,
          onPressed: onPressed,
          onPaymentResult: (result) async {
            await runGooglePay(result, amountInCents: priceInCents);
            if (onSuccess != null) onSuccess!();
          },
          paymentItems: [paymentItem],
          type: p.GooglePayButtonType.donate,
          paymentConfiguration:
              p.PaymentConfiguration.fromJsonString(googlePayConfig));
    }
    return Container();
  }
}