Hi all,
I'm trying to implement a slider that add a certain value to the initial value when checking out. But I'm not able to pass that extra value to my checkout API Call.
Here an example:
https://imgur.com/a/mp5ytzW
Structure: PaymentWidget => DonateView => DonateScreen
The API call fetchStripePaymentIntent is inside the DonateScreen initState and I want the value of the Slider in DonateView to be inside the API call.
I usually know how to do it, but it's not working this time. I would really appreciate any help.
What I have tried:
PaymentWidget:
class PaymentsWidget extends StatelessWidget {
final StripePaymentIntent stripePaymentIntent;
final int conversationId;
PaymentsWidget(this.stripePaymentIntent, this.conversationId, {Key? key}) : super(key: key) {
isApplePaySupported();
}
isApplePaySupported() {
print("Apple pay supported ${Stripe.instance.isApplePaySupported.value} ");
}
Future<void> checkout(BuildContext context) async {
Stripe.stripeAccountId = stripePaymentIntent.stripeAccountId;
await Stripe.instance.initPaymentSheet(
paymentSheetParameters: SetupPaymentSheetParameters(
applePay: true,
googlePay: true,
style: ThemeMode.light,
testEnv: Config.stripeTestEnv,
merchantCountryCode: 'DE',
merchantDisplayName: 'TrödelSpende',
paymentIntentClientSecret: stripePaymentIntent.client_secret,
));
try {
await Stripe.instance.presentPaymentSheet();
context.router.replace(DonationSuccessfulRoute(
itemId: stripePaymentIntent.itemId, conversationId: conversationId));
} on Exception catch (e) {
if (e is StripeException) {
if (e.error.code == FailureCode.Canceled) {
print("Stripe payment canceled");
} else {
print("StripeException");
print(e.error);
}
} else {
print("Error");
print(e);
}
}
}
@override
Widget build(BuildContext context) {
return SizedBox(
width: double.infinity,
child: ElevatedButton(
style: ButtonStyle(backgroundColor: MaterialStateProperty.all<Color>(MyTheme.orange)),
onPressed: () => checkout(context),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"PayNow".tr(),
style: MyTheme.buttonText,
),
],
),
),
);
}
}
DonateView:
class DonateView extends StatefulWidget {
final StripePaymentIntent spi;
final Item item;
final UserProfile? userProfile;
final int conversationId;
final NgoDetails ngo;
int extra;
DonateView(this.spi, this.item, this.userProfile, this.conversationId, this.ngo, this.extra,
{Key? key})
: super(key: key);
@override
State<DonateView> createState() => _DonateViewState();
}
class _DonateViewState extends State<DonateView> {
@override
Widget build(BuildContext context) {
const sizedBoxSpace = SizedBox(height: 24);
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
sizedBoxSpace,
UserProfileWidget(widget.userProfile),
sizedBoxSpace,
Text(
"donate1".tr(args: [widget.userProfile!.firstname]),
style: MyTheme.black,
),
Text("donate2".tr(), style: MyTheme.black),
const SizedBox(height: 10),
Text("donate3".tr(), style: MyTheme.orange600),
sizedBoxSpace,
RichText(
text: TextSpan(
style: MyTheme.mediumBlack,
children: <TextSpan>[
TextSpan(text: 'donate4'.tr()),
TextSpan(
text: Utils.getDisplayPrice(widget.item.amountInCent + widget.extra),
style: const TextStyle(color: MyTheme.orange)),
TextSpan(text: 'donate5'.tr()),
TextSpan(text: widget.ngo.name, style: const TextStyle(color: MyTheme.primary)),
TextSpan(text: 'donate6'.tr()),
],
),
),
sizedBoxSpace,
getSlider(context),
sizedBoxSpace,
PaymentsWidget(
widget.spi,
widget.conversationId,
),
],
));
}
Widget getSlider(BuildContext context) {
return Slider(
min: 0,
max: 2000,
label: widget.extra.toString(),
value: widget.extra.toDouble(),
onChanged: ((value) {
setState(() {
widget.extra = value.toInt();
});
}),
);
}
}
DonateScreen:
class DonateScreen extends StatefulWidget {
final int itemId;
final int conversationId;
final int extraInCent;
DonateScreen(@pathParam this.itemId, @pathParam this.conversationId, @pathParam this.extraInCent,
{Key? key})
: super(key: key);
@override
_DonateScreenState createState() => _DonateScreenState();
}
class _DonateScreenState extends State<DonateScreen> {
late Future<StripePaymentIntent> _stripePaymentIntent;
@override
void initState() {
super.initState();
setState(() {
_stripePaymentIntent = Provider.of<PaymentIntentProvider>(context, listen: false)
.fetchStripePaymentIntent(widget.itemId, widget.extraInCent);
});
}
@override
Widget build(BuildContext context) {
return BlocBuilder<ItemBloc, ItemState>(
builder: (context, state) {
if (state is ItemLoadedState) {
Item item = state.item;
return Scaffold(
appBar: AppBar(
title: Text(
"Pay".tr(),
),
),
body: SingleChildScrollView(
child: BlocBuilder<ProfileBloc, ProfileState>(
builder: ((context, state) {
if (state is ProfileLoadedState) {
UserProfile userProfile = state.userProfile;
return FutureBuilder<StripePaymentIntent>(
future: _stripePaymentIntent,
builder:
(BuildContext context, AsyncSnapshot<StripePaymentIntent> snapshot) {
List<Widget> children;
if (snapshot.hasData) {
Item theItem = item;
children = <Widget>[
BlocBuilder<NgosBloc, NgosState>(
builder: (context, state) {
if (state is NgosLoadedState) {
return Column(
children: [
DonateView(
snapshot.data!,
theItem,
userProfile,
widget.conversationId,
state.ngos[item.ngoId]!,
widget.extraInCent,
),
],
);
}
return Container();
},
),
];
} else if (snapshot.hasError) {
children = <Widget>[
const Icon(
Icons.error_outline,
color: Colors.red,
size: 60,
),
Padding(
padding: const EdgeInsets.only(top: 16),
child: Text('Error: $snapshot.error'),
),
];
} else {
children = const <Widget>[
SizedBox(
width: 60,
height: 60,
child: MyCircularProgressIndicator(),
)
];
}
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: children,
),
);
});
}
return Container();
}),
),
),
);
}
return Container();
},
);
}
}