Added quote expiry-aware flows with auto-refresh #211
@@ -84,12 +84,9 @@ class QuotationProvider extends ChangeNotifier {
|
|||||||
return _lastRequestSignature == _signature(_pendingIntent!);
|
return _lastRequestSignature == _signature(_pendingIntent!);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool get hasLiveQuote =>
|
bool get isReady => _isLoaded && !_isExpired && !_quotation.isLoading && _quotation.error == null;
|
||||||
|
|
|||||||
_isLoaded &&
|
|
||||||
!_isExpired &&
|
bool get hasLiveQuote => isReady && quotation != null;
|
||||||
!_quotation.isLoading &&
|
|
||||||
_quotation.error == null &&
|
|
||||||
quotation != null;
|
|
||||||
|
|
||||||
Duration? get timeToExpire {
|
Duration? get timeToExpire {
|
||||||
final expiresAt = _quoteExpiry;
|
final expiresAt = _quoteExpiry;
|
||||||
@@ -176,9 +173,10 @@ class QuotationProvider extends ChangeNotifier {
|
|||||||
|
|
||||||
void refreshNow({bool force = true}) {
|
void refreshNow({bool force = true}) {
|
||||||
_debounceTimer?.cancel();
|
_debounceTimer?.cancel();
|
||||||
if (!_organizationAttached) return;
|
if (!canRequestQuote) {
|
||||||
if (_pendingIntent == null) {
|
if (_pendingIntent == null) {
|
||||||
_reset();
|
_reset();
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
unawaited(_requestQuotation(_pendingIntent!, force: force));
|
unawaited(_requestQuotation(_pendingIntent!, force: force));
|
||||||
|
|||||||
@@ -15,8 +15,6 @@ import 'package:pweb/pages/payment_methods/payment_page/body.dart';
|
|||||||
import 'package:pweb/widgets/sidebar/destinations.dart';
|
import 'package:pweb/widgets/sidebar/destinations.dart';
|
||||||
import 'package:pweb/services/posthog.dart';
|
import 'package:pweb/services/posthog.dart';
|
||||||
|
|
||||||
import 'package:pweb/generated/i18n/app_localizations.dart';
|
|
||||||
|
|
||||||
|
|
||||||
class PaymentPage extends StatefulWidget {
|
class PaymentPage extends StatefulWidget {
|
||||||
final ValueChanged<Recipient?>? onBack;
|
final ValueChanged<Recipient?>? onBack;
|
||||||
@@ -85,16 +83,12 @@ class _PaymentPageState extends State<PaymentPage> {
|
|||||||
final flowProvider = context.read<PaymentFlowProvider>();
|
final flowProvider = context.read<PaymentFlowProvider>();
|
||||||
final paymentProvider = context.read<PaymentProvider>();
|
final paymentProvider = context.read<PaymentProvider>();
|
||||||
final quotationProvider = context.read<QuotationProvider>();
|
final quotationProvider = context.read<QuotationProvider>();
|
||||||
final loc = AppLocalizations.of(context)!;
|
|
||||||
if (paymentProvider.isLoading) return;
|
if (paymentProvider.isLoading) return;
|
||||||
|
|
||||||
if (!quotationProvider.hasLiveQuote) {
|
if (!quotationProvider.hasLiveQuote) {
|
||||||
if (quotationProvider.canRequestQuote) {
|
if (quotationProvider.canRequestQuote) {
|
||||||
quotationProvider.refreshNow();
|
quotationProvider.refreshNow();
|
||||||
}
|
}
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(content: Text(quotationProvider.canRequestQuote ? loc.quoteExpired : loc.quoteUnavailable)),
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,9 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
|
|
||||||
import 'package:pshared/models/payment/wallet.dart';
|
import 'package:pshared/models/payment/wallet.dart';
|
||||||
import 'package:pshared/models/recipient/recipient.dart';
|
import 'package:pshared/models/recipient/recipient.dart';
|
||||||
import 'package:pshared/provider/payment/provider.dart';
|
|
||||||
import 'package:pshared/provider/payment/quotation.dart';
|
|
||||||
import 'package:pshared/provider/recipient/provider.dart';
|
import 'package:pshared/provider/recipient/provider.dart';
|
||||||
|
|
||||||
import 'package:pweb/models/button_state.dart';
|
|
||||||
import 'package:pweb/pages/dashboard/payouts/form.dart';
|
import 'package:pweb/pages/dashboard/payouts/form.dart';
|
||||||
import 'package:pweb/pages/payment_methods/payment_page/back_button.dart';
|
import 'package:pweb/pages/payment_methods/payment_page/back_button.dart';
|
||||||
import 'package:pweb/pages/payment_methods/payment_page/header.dart';
|
import 'package:pweb/pages/payment_methods/payment_page/header.dart';
|
||||||
@@ -103,18 +98,7 @@ class PaymentPageContent extends StatelessWidget {
|
|||||||
SizedBox(height: dimensions.paddingLarge),
|
SizedBox(height: dimensions.paddingLarge),
|
||||||
const QuoteStatus(),
|
const QuoteStatus(),
|
||||||
SizedBox(height: dimensions.paddingXXLarge),
|
SizedBox(height: dimensions.paddingXXLarge),
|
||||||
Consumer2<QuotationProvider, PaymentProvider>(
|
SendButton(onPressed: onSend),
|
||||||
builder: (context, quotation, payment, _) {
|
|
||||||
final canSend = quotation.hasLiveQuote && !payment.isLoading;
|
|
||||||
final state = payment.isLoading
|
|
||||||
? ButtonState.loading
|
|
||||||
: (canSend ? ButtonState.enabled : ButtonState.disabled);
|
|
||||||
return SendButton(
|
|
||||||
onPressed: canSend ? onSend : null,
|
|
||||||
state: state,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
SizedBox(height: dimensions.paddingLarge),
|
SizedBox(height: dimensions.paddingLarge),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import 'package:pshared/provider/payment/provider.dart';
|
||||||
|
import 'package:pshared/provider/payment/quotation.dart';
|
||||||
|
|
||||||
import 'package:pweb/models/button_state.dart';
|
import 'package:pweb/models/button_state.dart';
|
||||||
import 'package:pweb/utils/dimensions.dart';
|
import 'package:pweb/utils/dimensions.dart';
|
||||||
|
|
||||||
@@ -8,20 +13,25 @@ import 'package:pweb/generated/i18n/app_localizations.dart';
|
|||||||
|
|
||||||
class SendButton extends StatelessWidget {
|
class SendButton extends StatelessWidget {
|
||||||
final VoidCallback? onPressed;
|
final VoidCallback? onPressed;
|
||||||
final ButtonState state;
|
|
||||||
|
|
||||||
|
tech
commented
а кнопка из провайдера не может состояние свое прочитать? нужно управление снаружи? а кнопка из провайдера не может состояние свое прочитать? нужно управление снаружи?
|
|||||||
const SendButton({
|
const SendButton({
|
||||||
super.key,
|
super.key,
|
||||||
required this.onPressed,
|
required this.onPressed,
|
||||||
this.state = ButtonState.enabled,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) => Consumer2<QuotationProvider, PaymentProvider>(
|
||||||
|
builder: (context, quotation, payment, _) {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final dimensions = AppDimensions();
|
final dimensions = AppDimensions();
|
||||||
|
|
||||||
|
final canSend = quotation.hasLiveQuote && !payment.isLoading;
|
||||||
|
final state = payment.isLoading
|
||||||
|
? ButtonState.loading
|
||||||
|
: (canSend ? ButtonState.enabled : ButtonState.disabled);
|
||||||
final isLoading = state == ButtonState.loading;
|
final isLoading = state == ButtonState.loading;
|
||||||
final isActive = state == ButtonState.enabled && onPressed != null && !isLoading;
|
final isActive = state == ButtonState.enabled && onPressed != null;
|
||||||
|
|
||||||
final backgroundColor = isActive
|
final backgroundColor = isActive
|
||||||
? theme.colorScheme.primary
|
? theme.colorScheme.primary
|
||||||
: theme.colorScheme.primary.withValues(alpha: 0.5);
|
: theme.colorScheme.primary.withValues(alpha: 0.5);
|
||||||
@@ -61,5 +71,6 @@ class SendButton extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user
часть выражения можно заменить галкой isReady и не повторять ее содержимое внутри этой галки