Skip to content

Commit

Permalink
Sync (#217)
Browse files Browse the repository at this point in the history
* sync android code from react native

* BREAKING: rename confirmpaymentmethod to confirmpayment

* update token result object

* add methods blur, focus and clear to cardfield

* make sure CardEditEvent is not exported by extracting it to a different file

* Update iOS side

* Display error also in debug

* Update focus and blur methods on iOS

Co-authored-by: Remon <[email protected]>
Co-authored-by: Jaime Blasco <[email protected]>
  • Loading branch information
3 people authored Jul 21, 2021
1 parent 82e9023 commit ae51739
Show file tree
Hide file tree
Showing 28 changed files with 345 additions and 177 deletions.
2 changes: 1 addition & 1 deletion example/lib/screens/google_pay_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ class _GooglePayScreenState extends State<GooglePayScreen> {
);

// 3. Confirm Google pay payment method
await Stripe.instance.confirmPaymentMethod(
await Stripe.instance.confirmPayment(
clientSecret,
params,
);
Expand Down
161 changes: 97 additions & 64 deletions example/lib/screens/no_webhook_payment_screen.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:flutter_stripe/flutter_stripe.dart';
import 'package:http/http.dart' as http;
import 'package:stripe_example/widgets/loading_button.dart';
import 'package:stripe_platform_interface/stripe_platform_interface.dart';

Expand All @@ -15,6 +15,13 @@ class NoWebhookPaymentScreen extends StatefulWidget {

class _NoWebhookPaymentScreenState extends State<NoWebhookPaymentScreen> {
CardFieldInputDetails? _card;
final _editController = CardEditController();

@override
void dispose() {
_editController.dispose();
super.dispose();
}

@override
Widget build(BuildContext context) {
Expand All @@ -25,6 +32,7 @@ class _NoWebhookPaymentScreenState extends State<NoWebhookPaymentScreen> {
Padding(
padding: EdgeInsets.all(16),
child: CardField(
controller: _editController,
onCardChanged: (card) {
setState(() {
_card = card;
Expand All @@ -39,6 +47,32 @@ class _NoWebhookPaymentScreenState extends State<NoWebhookPaymentScreen> {
text: 'Pay',
),
),
Divider(
thickness: 2,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 16),
child: ElevatedButton(
onPressed: () => _editController.blur(),
child: Text('Blur'),
),
),
ElevatedButton(
onPressed: () => _editController.clear(),
child: Text('Clear'),
),
Padding(
padding: const EdgeInsets.only(left: 16.0),
child: ElevatedButton(
onPressed: () => _editController.focus(),
child: Text('Focus'),
),
),
],
),
],
),
);
Expand All @@ -50,82 +84,81 @@ class _NoWebhookPaymentScreenState extends State<NoWebhookPaymentScreen> {
}

try {
// 1. Gather customer billing information (ex. email)

final billingDetails = BillingDetails(
email: '[email protected]',
phone: '+48888000888',
address: Address(
city: 'Houston',
country: 'US',
line1: '1459 Circle Drive',
line2: '',
state: 'Texas',
postalCode: '77063',
),
); // mocked data for tests

// 2. Create payment method
final paymentMethod =
await Stripe.instance.createPaymentMethod(PaymentMethodParams.card(
billingDetails: billingDetails,
));

// 3. call API to create PaymentIntent
final paymentIntentResult = await callNoWebhookPayEndpointMethodId(
useStripeSdk: true,
paymentMethodId: paymentMethod.id,
currency: 'usd', // mocked data
items: [
{'id': 'id'}
],
);

// 1. Gather customer billing information (ex. email)

final billingDetails = BillingDetails(
email: '[email protected]',
phone: '+48888000888',
address: Address(
city: 'Houston',
country: 'US',
line1: '1459 Circle Drive',
line2: '',
state: 'Texas',
postalCode: '77063',
),
); // mocked data for tests

// 2. Create payment method
final paymentMethod =
await Stripe.instance.createPaymentMethod(PaymentMethodParams.card(
billingDetails: billingDetails,
));

// 3. call API to create PaymentIntent
final paymentIntentResult = await callNoWebhookPayEndpointMethodId(
useStripeSdk: true,
paymentMethodId: paymentMethod.id,
currency: 'usd', // mocked data
items: [
{'id': 'id'}
],
);

if (paymentIntentResult['error'] != null) {
// Error during creating or confirming Intent
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error: ${paymentIntentResult['error']}')));
return;
}
if (paymentIntentResult['error'] != null) {
// Error during creating or confirming Intent
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error: ${paymentIntentResult['error']}')));
return;
}

if (paymentIntentResult['clientSecret'] != null &&
paymentIntentResult['requiresAction'] == null) {
// Payment succedeed
if (paymentIntentResult['clientSecret'] != null &&
paymentIntentResult['requiresAction'] == null) {
// Payment succedeed

ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('Success!: The payment was confirmed successfully!')));
return;
}
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content:
Text('Success!: The payment was confirmed successfully!')));
return;
}

if (paymentIntentResult['clientSecret'] != null &&
paymentIntentResult['requiresAction'] == true) {
// 4. if payment requires action calling handleCardAction
final paymentIntent = await Stripe.instance
.handleCardAction(paymentIntentResult['clientSecret']);
if (paymentIntentResult['clientSecret'] != null &&
paymentIntentResult['requiresAction'] == true) {
// 4. if payment requires action calling handleCardAction
final paymentIntent = await Stripe.instance
.handleCardAction(paymentIntentResult['clientSecret']);

// todo handle error
/*if (cardActionError) {
// todo handle error
/*if (cardActionError) {
Alert.alert(
`Error code: ${cardActionError.code}`,
cardActionError.message
);
} else*/

if (paymentIntent.status == PaymentIntentsStatus.RequiresConfirmation) {
// 5. Call API to confirm intent
await confirmIntent(paymentIntent.id);
} else {
// Payment succedeed
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error: ${paymentIntentResult['error']}')));
if (paymentIntent.status == PaymentIntentsStatus.RequiresConfirmation) {
// 5. Call API to confirm intent
await confirmIntent(paymentIntent.id);
} else {
// Payment succedeed
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('Error: ${paymentIntentResult['error']}')));
}
}
}

} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error: $e')));
rethrow;
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('Error: $e')));
rethrow;
}
}

Expand Down
2 changes: 1 addition & 1 deletion example/lib/screens/setup_future_payment_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ class _SetupFuturePaymentScreenState extends State<SetupFuturePaymentScreen> {

// TODO lastPaymentError
if (_retrievedPaymentIntent?.paymentMethodId != null && _card != null) {
await Stripe.instance.confirmPaymentMethod(
await Stripe.instance.confirmPayment(
_retrievedPaymentIntent!.clientSecret,
PaymentMethodParams.cardFromMethodId(
paymentMethodId: _retrievedPaymentIntent!.paymentMethodId!),
Expand Down
2 changes: 1 addition & 1 deletion example/lib/screens/webhook_payment_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ class _WebhookPaymentScreenState extends State<WebhookPaymentScreen> {
// 3. Confirm payment with card details
// The rest will be done automatically using webhooks
// ignore: unused_local_variable
final paymentIntent = await Stripe.instance.confirmPaymentMethod(
final paymentIntent = await Stripe.instance.confirmPayment(
clientSecret['clientSecret'],
PaymentMethodParams.card(
billingDetails: billingDetails,
Expand Down
9 changes: 2 additions & 7 deletions example/lib/widgets/loading_button.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,22 +29,17 @@ class _LoadingButtonState extends State<LoadingButton> {
setState(() {
_isLoading = true;
});

try {
await widget.onPressed!();
} catch (e) {
if (kDebugMode) {
rethrow;
} else {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('Error $e')));
}
rethrow;
} finally {
setState(() {
_isLoading = false;
});
}


}
}
1 change: 1 addition & 0 deletions packages/stripe/lib/flutter_stripe.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export 'src/model/apple_pay_button.dart';
export 'src/stripe.dart';
export 'src/widgets/apple_pay_button.dart';
export 'src/widgets/card_field.dart';
export 'src/widgets/card_edit_controller.dart';
12 changes: 7 additions & 5 deletions packages/stripe/lib/src/stripe.dart
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ class Stripe {

/// Retrieves a [PaymentIntent] using the provided [clientSecret].
///
/// Throws a [StripeException] in case retrieving the intent fails.
/// Throws a [StripeException] in case retrieving the intent fails.
Future<PaymentIntent> retrievePaymentIntent(String clientSecret) async {
await _awaitForSettings();
try {
Expand Down Expand Up @@ -207,16 +207,18 @@ class Stripe {
/// Confirms a payment method, using the provided [paymentIntentClientSecret]
/// and [data].
///
/// See [PaymentMethodParams] for more details.
/// Throws a [StripeException] when confirming the paymentmethod fails.
Future<PaymentIntent> confirmPaymentMethod(
/// See [PaymentMethodParams] for more details. The method returns a
/// [PaymentIntent]. Throws a [StripeException] when confirming the
/// paymentmethod fails.
Future<PaymentIntent> confirmPayment(
String paymentIntentClientSecret,
PaymentMethodParams data, [
Map<String, String> options = const {},
]) async {
await _awaitForSettings();
try {
final paymentMethod = await _platform.confirmPaymentMethod(
final paymentMethod = await _platform.confirmPayment(
paymentIntentClientSecret, data, options);
return paymentMethod;
} on StripeError {
Expand Down
22 changes: 22 additions & 0 deletions packages/stripe/lib/src/widgets/card_edit_controller.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import 'package:flutter/material.dart';

import 'card_edit_event.dart';

class CardEditController extends ValueNotifier<CardEditEvent> {
CardEditController() : super(CardEditEvent.none);

void focus() {
value = CardEditEvent.focus;
notifyListeners();
}

void blur() {
value = CardEditEvent.blur;
notifyListeners();
}

void clear() {
value = CardEditEvent.clear;
notifyListeners();
}
}
1 change: 1 addition & 0 deletions packages/stripe/lib/src/widgets/card_edit_event.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
enum CardEditEvent { none, focus, blur, clear }
Loading

0 comments on commit ae51739

Please sign in to comment.