quotation rate display
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -9,4 +9,5 @@ untranslated.txt
|
|||||||
generate_protos.sh
|
generate_protos.sh
|
||||||
update_dep.sh
|
update_dep.sh
|
||||||
.vscode/
|
.vscode/
|
||||||
.gocache/
|
.gocache/
|
||||||
|
.cache/
|
||||||
18
frontend/pshared/lib/models/asset.dart
Normal file
18
frontend/pshared/lib/models/asset.dart
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import 'package:pshared/models/currency.dart';
|
||||||
|
import 'package:pshared/utils/currency.dart';
|
||||||
|
|
||||||
|
|
||||||
|
class Asset {
|
||||||
|
final Currency currency;
|
||||||
|
final double amount;
|
||||||
|
|
||||||
|
const Asset({
|
||||||
|
required this.currency,
|
||||||
|
required this.amount,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Asset createAsset(String currencyCode, String amount) => Asset(
|
||||||
|
currency: currencyStringToCode(currencyCode),
|
||||||
|
amount: double.parse(amount),
|
||||||
|
);
|
||||||
20
frontend/pshared/lib/provider/payment/amount.dart
Normal file
20
frontend/pshared/lib/provider/payment/amount.dart
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
|
||||||
|
class PaymentAmountProvider with ChangeNotifier {
|
||||||
|
double _amount = 10.0;
|
||||||
|
bool _payerCoversFee = true;
|
||||||
|
|
||||||
|
double get amount => _amount;
|
||||||
|
bool get payerCoversFee => _payerCoversFee;
|
||||||
|
|
||||||
|
void setAmount(double value) {
|
||||||
|
_amount = value;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPayerCoversFee(bool value) {
|
||||||
|
_payerCoversFee = value;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,17 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:pshared/models/asset.dart';
|
||||||
|
|
||||||
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
|
import 'package:pshared/models/payment/currency_pair.dart';
|
||||||
|
import 'package:pshared/models/payment/fx/intent.dart';
|
||||||
|
import 'package:pshared/models/payment/fx/side.dart';
|
||||||
|
import 'package:pshared/models/payment/kind.dart';
|
||||||
|
import 'package:pshared/models/payment/methods/card.dart';
|
||||||
|
import 'package:pshared/models/payment/methods/managed_wallet.dart';
|
||||||
|
import 'package:pshared/models/payment/money.dart';
|
||||||
|
import 'package:pshared/models/payment/settlement_mode.dart';
|
||||||
|
import 'package:pshared/provider/payment/amount.dart';
|
||||||
import 'package:pshared/api/requests/payment/quote.dart';
|
import 'package:pshared/api/requests/payment/quote.dart';
|
||||||
import 'package:pshared/data/mapper/payment/intent/payment.dart';
|
import 'package:pshared/data/mapper/payment/intent/payment.dart';
|
||||||
import 'package:pshared/models/payment/intent.dart';
|
import 'package:pshared/models/payment/intent.dart';
|
||||||
@@ -7,7 +19,6 @@ import 'package:pshared/models/payment/quote.dart';
|
|||||||
import 'package:pshared/provider/organizations.dart';
|
import 'package:pshared/provider/organizations.dart';
|
||||||
import 'package:pshared/provider/resource.dart';
|
import 'package:pshared/provider/resource.dart';
|
||||||
import 'package:pshared/service/payment/quotation.dart';
|
import 'package:pshared/service/payment/quotation.dart';
|
||||||
import 'package:uuid/uuid.dart';
|
|
||||||
|
|
||||||
|
|
||||||
class QuotationProvider extends ChangeNotifier {
|
class QuotationProvider extends ChangeNotifier {
|
||||||
@@ -15,14 +26,46 @@ class QuotationProvider extends ChangeNotifier {
|
|||||||
late OrganizationsProvider _organizations;
|
late OrganizationsProvider _organizations;
|
||||||
bool _isLoaded = false;
|
bool _isLoaded = false;
|
||||||
|
|
||||||
void update(OrganizationsProvider venue) {
|
void update(OrganizationsProvider venue, PaymentAmountProvider payment) {
|
||||||
_organizations = venue;
|
_organizations = venue;
|
||||||
|
getQuotation(PaymentIntent(
|
||||||
|
kind: PaymentKind.payout,
|
||||||
|
amount: Money(
|
||||||
|
amount: payment.amount.toString(),
|
||||||
|
currency: 'USDT',
|
||||||
|
),
|
||||||
|
destination: CardPaymentMethod(
|
||||||
|
pan: '4000000000000077',
|
||||||
|
firstName: 'John',
|
||||||
|
lastName: 'Doe',
|
||||||
|
),
|
||||||
|
source: ManagedWalletPaymentMethod(
|
||||||
|
managedWalletRef: '',
|
||||||
|
),
|
||||||
|
fx: FxIntent(
|
||||||
|
pair: CurrencyPair(
|
||||||
|
base: 'USDT',
|
||||||
|
quote: 'RUB',
|
||||||
|
),
|
||||||
|
side: FxSide.sellBaseBuyQuote,
|
||||||
|
),
|
||||||
|
settlementMode: payment.payerCoversFee ? SettlementMode.fixReceived : SettlementMode.fixSource,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
PaymentQuote? get quotation => _quotation.data;
|
PaymentQuote? get quotation => _quotation.data;
|
||||||
|
|
||||||
bool get isReady => _isLoaded && !_quotation.isLoading && _quotation.error == null;
|
bool get isReady => _isLoaded && !_quotation.isLoading && _quotation.error == null;
|
||||||
|
|
||||||
|
Asset? get fee => quotation == null ? null : createAsset(quotation!.expectedFeeTotal!.currency, quotation!.expectedFeeTotal!.amount);
|
||||||
|
Asset? get total => quotation == null ? null : createAsset(quotation!.debitAmount!.currency, quotation!.debitAmount!.amount);
|
||||||
|
Asset? get recipientGets => quotation == null ? null : createAsset(quotation!.expectedSettlementAmount!.currency, quotation!.expectedSettlementAmount!.amount);
|
||||||
|
|
||||||
|
void _setResource(Resource<PaymentQuote> quotation) {
|
||||||
|
_quotation = quotation;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
Future<PaymentQuote?> getQuotation(PaymentIntent intent) async {
|
Future<PaymentQuote?> getQuotation(PaymentIntent intent) async {
|
||||||
if (!_organizations.isOrganizationSet) throw StateError('Organization is not set');
|
if (!_organizations.isOrganizationSet) throw StateError('Organization is not set');
|
||||||
try {
|
try {
|
||||||
@@ -35,19 +78,20 @@ class QuotationProvider extends ChangeNotifier {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
_isLoaded = true;
|
_isLoaded = true;
|
||||||
_quotation = _quotation.copyWith(data: response, isLoading: false);
|
_setResource(_quotation.copyWith(data: response, isLoading: false, error: null));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
_quotation = _quotation.copyWith(
|
_setResource(_quotation.copyWith(
|
||||||
|
data: null,
|
||||||
error: e is Exception ? e : Exception(e.toString()),
|
error: e is Exception ? e : Exception(e.toString()),
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
return _quotation.data;
|
return _quotation.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset() {
|
void reset() {
|
||||||
_quotation = Resource(data: null, isLoading: false, error: null);
|
_setResource(Resource(data: null, isLoading: false, error: null));
|
||||||
_isLoaded = false;
|
_isLoaded = false;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import 'package:pshared/api/requests/payment/quote.dart';
|
|||||||
import 'package:pshared/api/responses/payment/quotation.dart';
|
import 'package:pshared/api/responses/payment/quotation.dart';
|
||||||
import 'package:pshared/data/mapper/payment/payment_quote.dart';
|
import 'package:pshared/data/mapper/payment/payment_quote.dart';
|
||||||
import 'package:pshared/models/payment/quote.dart';
|
import 'package:pshared/models/payment/quote.dart';
|
||||||
|
import 'package:pshared/service/authorization/service.dart';
|
||||||
import 'package:pshared/service/services.dart';
|
import 'package:pshared/service/services.dart';
|
||||||
import 'package:pshared/utils/http/requests.dart';
|
|
||||||
|
|
||||||
|
|
||||||
class QuotationService {
|
class QuotationService {
|
||||||
@@ -14,7 +14,11 @@ class QuotationService {
|
|||||||
|
|
||||||
static Future<PaymentQuote> getQuotation(String organizationRef, QuotePaymentRequest request) async {
|
static Future<PaymentQuote> getQuotation(String organizationRef, QuotePaymentRequest request) async {
|
||||||
_logger.fine('Quoting payment for organization $organizationRef');
|
_logger.fine('Quoting payment for organization $organizationRef');
|
||||||
final response = await getPOSTResponse(_objectType, '/quote/$organizationRef', request.toJson());
|
final response = await AuthorizationService.getPOSTResponse(
|
||||||
|
_objectType,
|
||||||
|
'/quote/$organizationRef',
|
||||||
|
request.toJson(),
|
||||||
|
);
|
||||||
return PaymentQuoteResponse.fromJson(response).quote.toDomain();
|
return PaymentQuoteResponse.fromJson(response).quote.toDomain();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,64 @@
|
|||||||
String currencyCodeToSymbol(String currencyCode) {
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'package:pshared/models/asset.dart';
|
||||||
|
import 'package:pshared/models/currency.dart';
|
||||||
|
|
||||||
|
|
||||||
|
String currencyCodeToSymbol(Currency currencyCode) {
|
||||||
switch (currencyCode) {
|
switch (currencyCode) {
|
||||||
case 'USD':
|
case Currency.usd:
|
||||||
return '\$';
|
return '\$';
|
||||||
case 'PLN':
|
case Currency.usdt:
|
||||||
return 'zł';
|
return '₮';
|
||||||
case 'EUR':
|
case Currency.usdc:
|
||||||
return '€';
|
return '\$';
|
||||||
case 'GBP':
|
case Currency.rub:
|
||||||
return '£';
|
|
||||||
case 'HUF':
|
|
||||||
return 'Ft';
|
|
||||||
case 'RUB':
|
|
||||||
return '₽';
|
return '₽';
|
||||||
default:
|
case Currency.eur:
|
||||||
return currencyCode;
|
return '€';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String currencyToString(String currencyCode, double amount) {
|
String amountToString(double amount) {
|
||||||
return '${currencyCodeToSymbol(currencyCode)}\u00A0${amount.toStringAsFixed(2)}';
|
return amount.toStringAsFixed(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
String currencyToString(Currency currencyCode, double amount) {
|
||||||
|
return '${currencyCodeToSymbol(currencyCode)}\u00A0${amountToString(amount)}';
|
||||||
|
}
|
||||||
|
|
||||||
|
String assetToString(Asset asset) {
|
||||||
|
return currencyToString(asset.currency, asset.amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
Currency currencyStringToCode(String currencyCode) {
|
||||||
|
switch (currencyCode) {
|
||||||
|
case 'USD':
|
||||||
|
return Currency.usd;
|
||||||
|
case 'USDT':
|
||||||
|
return Currency.usdt;
|
||||||
|
case 'USDC':
|
||||||
|
return Currency.usdc;
|
||||||
|
case 'RUB':
|
||||||
|
return Currency.rub;
|
||||||
|
case 'EUR':
|
||||||
|
return Currency.eur;
|
||||||
|
default:
|
||||||
|
throw ArgumentError('Unknown currency code: $currencyCode');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IconData iconForCurrencyType(Currency currencyCode) {
|
||||||
|
switch (currencyCode) {
|
||||||
|
case Currency.usd:
|
||||||
|
return Icons.currency_exchange;
|
||||||
|
case Currency.eur:
|
||||||
|
return Icons.currency_exchange;
|
||||||
|
case Currency.rub:
|
||||||
|
return Icons.currency_ruble;
|
||||||
|
case Currency.usdt:
|
||||||
|
return Icons.currency_exchange;
|
||||||
|
case Currency.usdc:
|
||||||
|
return Icons.money;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:pshared/models/wallet/wallet.dart' as domain;
|
import 'package:pshared/models/wallet/wallet.dart' as domain;
|
||||||
|
|
||||||
import 'package:pweb/models/currency.dart';
|
import 'package:pshared/models/currency.dart';
|
||||||
|
|
||||||
import 'package:pweb/models/wallet.dart';
|
import 'package:pweb/models/wallet.dart';
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -378,7 +378,7 @@
|
|||||||
"send": "Send Payout",
|
"send": "Send Payout",
|
||||||
"recipientPaysFee": "Recipient pays the fee",
|
"recipientPaysFee": "Recipient pays the fee",
|
||||||
|
|
||||||
"sentAmount": "Sent amount: ${amount}",
|
"sentAmount": "Sent amount: {amount}",
|
||||||
"@sentAmount": {
|
"@sentAmount": {
|
||||||
"description": "Label showing the amount sent",
|
"description": "Label showing the amount sent",
|
||||||
"placeholders": {
|
"placeholders": {
|
||||||
@@ -388,7 +388,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
"fee": "Fee: ${fee}",
|
"fee": "Fee: {fee}",
|
||||||
"@fee": {
|
"@fee": {
|
||||||
"description": "Label showing the transaction fee",
|
"description": "Label showing the transaction fee",
|
||||||
"placeholders": {
|
"placeholders": {
|
||||||
@@ -398,7 +398,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
"recipientWillReceive": "Recipient will receive: ${amount}",
|
"recipientWillReceive": "Recipient will receive: {amount}",
|
||||||
"@recipientWillReceive": {
|
"@recipientWillReceive": {
|
||||||
"description": "Label showing how much the recipient will receive",
|
"description": "Label showing how much the recipient will receive",
|
||||||
"placeholders": {
|
"placeholders": {
|
||||||
@@ -408,7 +408,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
"total": "Total: ${total}",
|
"total": "Total: {total}",
|
||||||
"@total": {
|
"@total": {
|
||||||
"description": "Label showing the total amount of the transaction",
|
"description": "Label showing the total amount of the transaction",
|
||||||
"placeholders": {
|
"placeholders": {
|
||||||
|
|||||||
@@ -378,7 +378,7 @@
|
|||||||
"send": "Отправить выплату",
|
"send": "Отправить выплату",
|
||||||
"recipientPaysFee": "Получатель оплачивает комиссию",
|
"recipientPaysFee": "Получатель оплачивает комиссию",
|
||||||
|
|
||||||
"sentAmount": "Отправленная сумма: ${amount}",
|
"sentAmount": "Отправленная сумма: {amount}",
|
||||||
"@sentAmount": {
|
"@sentAmount": {
|
||||||
"description": "Метка, показывающая отправленную сумму",
|
"description": "Метка, показывающая отправленную сумму",
|
||||||
"placeholders": {
|
"placeholders": {
|
||||||
@@ -388,7 +388,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
"fee": "Комиссия: ${fee}",
|
"fee": "Комиссия: {fee}",
|
||||||
"@fee": {
|
"@fee": {
|
||||||
"description": "Метка, показывающая комиссию за транзакцию",
|
"description": "Метка, показывающая комиссию за транзакцию",
|
||||||
"placeholders": {
|
"placeholders": {
|
||||||
@@ -398,7 +398,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
"recipientWillReceive": "Получатель получит: ${amount}",
|
"recipientWillReceive": "Получатель получит: {amount}",
|
||||||
"@recipientWillReceive": {
|
"@recipientWillReceive": {
|
||||||
"description": "Метка, показывающая, сколько получит получатель",
|
"description": "Метка, показывающая, сколько получит получатель",
|
||||||
"placeholders": {
|
"placeholders": {
|
||||||
@@ -408,7 +408,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
"total": "Итого: ${total}",
|
"total": "Итого: {total}",
|
||||||
"@total": {
|
"@total": {
|
||||||
"description": "Метка, показывающая общую сумму транзакции",
|
"description": "Метка, показывающая общую сумму транзакции",
|
||||||
"placeholders": {
|
"placeholders": {
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import 'package:pshared/provider/locale.dart';
|
|||||||
import 'package:pshared/provider/permissions.dart';
|
import 'package:pshared/provider/permissions.dart';
|
||||||
import 'package:pshared/provider/account.dart';
|
import 'package:pshared/provider/account.dart';
|
||||||
import 'package:pshared/provider/organizations.dart';
|
import 'package:pshared/provider/organizations.dart';
|
||||||
import 'package:pshared/provider/payment/quotation.dart';
|
|
||||||
import 'package:pshared/provider/recipient/provider.dart';
|
import 'package:pshared/provider/recipient/provider.dart';
|
||||||
import 'package:pshared/provider/recipient/pmethods.dart';
|
import 'package:pshared/provider/recipient/pmethods.dart';
|
||||||
|
|
||||||
@@ -94,10 +93,6 @@ void main() async {
|
|||||||
ChangeNotifierProvider(
|
ChangeNotifierProvider(
|
||||||
create: (_) => OperationProvider(OperationService())..loadOperations(),
|
create: (_) => OperationProvider(OperationService())..loadOperations(),
|
||||||
),
|
),
|
||||||
ChangeNotifierProxyProvider<OrganizationsProvider, QuotationProvider>(
|
|
||||||
create: (_) => QuotationProvider(),
|
|
||||||
update: (context, orgnization, provider) => provider!..update(orgnization),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
child: const PayApp(),
|
child: const PayApp(),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import 'package:pweb/models/currency.dart';
|
import 'package:pshared/models/currency.dart';
|
||||||
|
|
||||||
|
|
||||||
class Wallet {
|
class Wallet {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import 'package:flutter/widgets.dart';
|
|||||||
|
|
||||||
import 'package:pshared/models/payment/status.dart';
|
import 'package:pshared/models/payment/status.dart';
|
||||||
|
|
||||||
import 'package:pweb/models/currency.dart';
|
import 'package:pshared/models/currency.dart';
|
||||||
|
|
||||||
import 'package:pweb/generated/i18n/app_localizations.dart';
|
import 'package:pweb/generated/i18n/app_localizations.dart';
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'package:pshared/utils/currency.dart';
|
||||||
|
|
||||||
import 'package:pweb/models/wallet.dart';
|
import 'package:pweb/models/wallet.dart';
|
||||||
import 'package:pweb/utils/currency.dart';
|
|
||||||
|
|
||||||
|
|
||||||
class BalanceAmount extends StatelessWidget {
|
class BalanceAmount extends StatelessWidget {
|
||||||
@@ -25,7 +27,7 @@ class BalanceAmount extends StatelessWidget {
|
|||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
wallet.isHidden ? '•••• $currencyBalance' : '${wallet.balance.toStringAsFixed(2)} $currencyBalance',
|
wallet.isHidden ? '•••• $currencyBalance' : '${amountToString(wallet.balance)} $currencyBalance',
|
||||||
style: textTheme.headlineSmall?.copyWith(
|
style: textTheme.headlineSmall?.copyWith(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: colorScheme.onSurface,
|
color: colorScheme.onSurface,
|
||||||
|
|||||||
74
frontend/pweb/lib/pages/dashboard/payouts/amount.dart
Normal file
74
frontend/pweb/lib/pages/dashboard/payouts/amount.dart
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import 'package:pshared/provider/payment/amount.dart';
|
||||||
|
import 'package:pshared/utils/currency.dart';
|
||||||
|
|
||||||
|
import 'package:pweb/generated/i18n/app_localizations.dart';
|
||||||
|
|
||||||
|
|
||||||
|
class PaymentAmountWidget extends StatefulWidget {
|
||||||
|
const PaymentAmountWidget({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<PaymentAmountWidget> createState() => _PaymentAmountWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _PaymentAmountWidgetState extends State<PaymentAmountWidget> {
|
||||||
|
late final TextEditingController _controller;
|
||||||
|
bool _isSyncingText = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
final initialAmount = context.read<PaymentAmountProvider>().amount;
|
||||||
|
_controller = TextEditingController(text: amountToString(initialAmount));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_controller.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
double? _parseAmount(String value) => double.tryParse(value.replaceAll(',', '.'));
|
||||||
|
|
||||||
|
void _syncTextWithAmount(double amount) {
|
||||||
|
final parsedText = _parseAmount(_controller.text);
|
||||||
|
if (parsedText != null && parsedText == amount) return;
|
||||||
|
|
||||||
|
final nextText = amountToString(amount);
|
||||||
|
_isSyncingText = true;
|
||||||
|
_controller.value = TextEditingValue(
|
||||||
|
text: nextText,
|
||||||
|
selection: TextSelection.collapsed(offset: nextText.length),
|
||||||
|
);
|
||||||
|
_isSyncingText = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onChanged(String value) {
|
||||||
|
if (_isSyncingText) return;
|
||||||
|
|
||||||
|
final parsed = _parseAmount(value);
|
||||||
|
if (parsed != null) {
|
||||||
|
context.read<PaymentAmountProvider>().setAmount(parsed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final amount = context.select<PaymentAmountProvider, double>((provider) => provider.amount);
|
||||||
|
_syncTextWithAmount(amount);
|
||||||
|
|
||||||
|
return TextField(
|
||||||
|
controller: _controller,
|
||||||
|
keyboardType: const TextInputType.numberWithOptions(decimal: true),
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: AppLocalizations.of(context)!.amount,
|
||||||
|
border: const OutlineInputBorder(),
|
||||||
|
),
|
||||||
|
onChanged: _onChanged,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
29
frontend/pweb/lib/pages/dashboard/payouts/fee_payer.dart
Normal file
29
frontend/pweb/lib/pages/dashboard/payouts/fee_payer.dart
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import 'package:pshared/provider/payment/amount.dart';
|
||||||
|
|
||||||
|
import 'package:pweb/generated/i18n/app_localizations.dart';
|
||||||
|
|
||||||
|
|
||||||
|
class FeePayerSwitch extends StatelessWidget {
|
||||||
|
final double spacing;
|
||||||
|
final TextStyle? style;
|
||||||
|
|
||||||
|
const FeePayerSwitch({super.key, required this.spacing, TextStyle? this.style});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => Consumer<PaymentAmountProvider>(
|
||||||
|
builder: (context, provider, _) => Row(
|
||||||
|
spacing: spacing,
|
||||||
|
children: [
|
||||||
|
Text(AppLocalizations.of(context)!.recipientPaysFee, style: style),
|
||||||
|
Switch(
|
||||||
|
value: !provider.payerCoversFee,
|
||||||
|
onChanged: (val) => provider.setPayerCoversFee(!val),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
43
frontend/pweb/lib/pages/dashboard/payouts/form.dart
Normal file
43
frontend/pweb/lib/pages/dashboard/payouts/form.dart
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'package:pweb/pages/dashboard/payouts/amount.dart';
|
||||||
|
import 'package:pweb/pages/dashboard/payouts/fee_payer.dart';
|
||||||
|
import 'package:pweb/pages/dashboard/payouts/summary/widget.dart';
|
||||||
|
|
||||||
|
import 'package:pweb/generated/i18n/app_localizations.dart';
|
||||||
|
|
||||||
|
|
||||||
|
class PaymentFormWidget extends StatelessWidget {
|
||||||
|
const PaymentFormWidget({super.key});
|
||||||
|
|
||||||
|
static const double _smallSpacing = 5;
|
||||||
|
static const double _mediumSpacing = 10;
|
||||||
|
static const double _largeSpacing = 16;
|
||||||
|
static const double _extraSpacing = 15;
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final theme = Theme.of(context);
|
||||||
|
final loc = AppLocalizations.of(context)!;
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(loc.details, style: theme.textTheme.titleMedium),
|
||||||
|
const SizedBox(height: _smallSpacing),
|
||||||
|
|
||||||
|
const PaymentAmountWidget(),
|
||||||
|
|
||||||
|
const SizedBox(height: _mediumSpacing),
|
||||||
|
|
||||||
|
FeePayerSwitch(spacing: _mediumSpacing, style: theme.textTheme.titleMedium),
|
||||||
|
|
||||||
|
const SizedBox(height: _largeSpacing),
|
||||||
|
|
||||||
|
const PaymentSummary(spacing: _extraSpacing),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
|
|
||||||
import 'package:pweb/providers/mock_payment.dart';
|
|
||||||
|
|
||||||
import 'package:pweb/generated/i18n/app_localizations.dart';
|
|
||||||
|
|
||||||
|
|
||||||
class PaymentFormWidget extends StatelessWidget {
|
|
||||||
const PaymentFormWidget({super.key});
|
|
||||||
|
|
||||||
static const double _smallSpacing = 5;
|
|
||||||
static const double _mediumSpacing = 10;
|
|
||||||
static const double _largeSpacing = 16;
|
|
||||||
static const double _extraSpacing = 15;
|
|
||||||
|
|
||||||
String _formatAmount(double amount) => amount.toStringAsFixed(2);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final provider = Provider.of<MockPaymentProvider>(context);
|
|
||||||
final theme = Theme.of(context);
|
|
||||||
final loc = AppLocalizations.of(context)!;
|
|
||||||
|
|
||||||
return Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(loc.details, style: theme.textTheme.titleMedium),
|
|
||||||
const SizedBox(height: _smallSpacing),
|
|
||||||
|
|
||||||
TextField(
|
|
||||||
keyboardType: const TextInputType.numberWithOptions(decimal: true),
|
|
||||||
decoration: InputDecoration(
|
|
||||||
labelText: loc.amount,
|
|
||||||
border: const OutlineInputBorder(),
|
|
||||||
),
|
|
||||||
onChanged: (val) {
|
|
||||||
final parsed = double.tryParse(val.replaceAll(',', '.')) ?? 0.0;
|
|
||||||
provider.setAmount(parsed);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
|
|
||||||
const SizedBox(height: _mediumSpacing),
|
|
||||||
|
|
||||||
Row(
|
|
||||||
spacing: _mediumSpacing,
|
|
||||||
children: [
|
|
||||||
Text(loc.recipientPaysFee, style: theme.textTheme.titleMedium),
|
|
||||||
Switch(
|
|
||||||
value: !provider.payerCoversFee,
|
|
||||||
onChanged: (val) => provider.setPayerCoversFee(!val),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
|
|
||||||
const SizedBox(height: _largeSpacing),
|
|
||||||
|
|
||||||
Align(
|
|
||||||
alignment: Alignment.center,
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
||||||
children: [
|
|
||||||
_SummaryRow(label: loc.sentAmount(_formatAmount(provider.amount)), style: theme.textTheme.titleMedium),
|
|
||||||
_SummaryRow(label: loc.fee(_formatAmount(provider.fee)), style: theme.textTheme.titleMedium),
|
|
||||||
_SummaryRow(label: loc.recipientWillReceive(_formatAmount(provider.recipientGets)), style: theme.textTheme.titleMedium),
|
|
||||||
|
|
||||||
const SizedBox(height: _extraSpacing),
|
|
||||||
|
|
||||||
_SummaryRow(
|
|
||||||
label: loc.total(_formatAmount(provider.total)),
|
|
||||||
style: theme.textTheme.titleMedium!.copyWith(fontWeight: FontWeight.w600),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _SummaryRow extends StatelessWidget {
|
|
||||||
final String label;
|
|
||||||
final TextStyle? style;
|
|
||||||
|
|
||||||
const _SummaryRow({required this.label, this.style});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Text(label, style: style);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
23
frontend/pweb/lib/pages/dashboard/payouts/summary/fee.dart
Normal file
23
frontend/pweb/lib/pages/dashboard/payouts/summary/fee.dart
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import 'package:pshared/provider/payment/quotation.dart';
|
||||||
|
|
||||||
|
import 'package:pweb/pages/dashboard/payouts/summary/row.dart';
|
||||||
|
|
||||||
|
import 'package:pweb/generated/i18n/app_localizations.dart';
|
||||||
|
|
||||||
|
|
||||||
|
class PaymentFeeRow extends StatelessWidget {
|
||||||
|
const PaymentFeeRow({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => Consumer<QuotationProvider>(
|
||||||
|
builder: (context, provider, _) => PaymentSummaryRow(
|
||||||
|
labelFactory: AppLocalizations.of(context)!.fee,
|
||||||
|
asset: provider.fee,
|
||||||
|
style: Theme.of(context).textTheme.titleMedium,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import 'package:pshared/provider/payment/quotation.dart';
|
||||||
|
|
||||||
|
import 'package:pweb/pages/dashboard/payouts/summary/row.dart';
|
||||||
|
|
||||||
|
import 'package:pweb/generated/i18n/app_localizations.dart';
|
||||||
|
|
||||||
|
|
||||||
|
class PaymentRecipientReceivesRow extends StatelessWidget {
|
||||||
|
const PaymentRecipientReceivesRow({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => Consumer<QuotationProvider>(
|
||||||
|
builder: (context, provider, _) => PaymentSummaryRow(
|
||||||
|
labelFactory: AppLocalizations.of(context)!.recipientWillReceive,
|
||||||
|
asset: provider.recipientGets,
|
||||||
|
style: Theme.of(context).textTheme.titleMedium,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
24
frontend/pweb/lib/pages/dashboard/payouts/summary/row.dart
Normal file
24
frontend/pweb/lib/pages/dashboard/payouts/summary/row.dart
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'package:pshared/models/asset.dart';
|
||||||
|
import 'package:pshared/utils/currency.dart';
|
||||||
|
|
||||||
|
|
||||||
|
class PaymentSummaryRow extends StatelessWidget {
|
||||||
|
final String Function(String) labelFactory;
|
||||||
|
final Asset? asset;
|
||||||
|
final TextStyle? style;
|
||||||
|
|
||||||
|
const PaymentSummaryRow({
|
||||||
|
super.key,
|
||||||
|
required this.labelFactory,
|
||||||
|
required this.asset,
|
||||||
|
this.style,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => Text(
|
||||||
|
labelFactory(asset == null ? 'N/A' : assetToString(asset!)),
|
||||||
|
style: style,
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import 'package:pshared/models/asset.dart';
|
||||||
|
import 'package:pshared/models/currency.dart';
|
||||||
|
import 'package:pshared/provider/payment/amount.dart';
|
||||||
|
|
||||||
|
import 'package:pweb/pages/dashboard/payouts/summary/row.dart';
|
||||||
|
|
||||||
|
import 'package:pweb/generated/i18n/app_localizations.dart';
|
||||||
|
|
||||||
|
|
||||||
|
class PaymentSentAmountRow extends StatelessWidget {
|
||||||
|
final Currency currency;
|
||||||
|
const PaymentSentAmountRow({super.key, required this.currency});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => Consumer<PaymentAmountProvider>(
|
||||||
|
builder: (context, provider, _) => PaymentSummaryRow(
|
||||||
|
labelFactory: AppLocalizations.of(context)!.sentAmount,
|
||||||
|
asset: Asset(currency: currency, amount: provider.amount),
|
||||||
|
style: Theme.of(context).textTheme.titleMedium,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
23
frontend/pweb/lib/pages/dashboard/payouts/summary/total.dart
Normal file
23
frontend/pweb/lib/pages/dashboard/payouts/summary/total.dart
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import 'package:pshared/provider/payment/quotation.dart';
|
||||||
|
|
||||||
|
import 'package:pweb/pages/dashboard/payouts/summary/row.dart';
|
||||||
|
|
||||||
|
import 'package:pweb/generated/i18n/app_localizations.dart';
|
||||||
|
|
||||||
|
|
||||||
|
class PaymentTotalRow extends StatelessWidget {
|
||||||
|
const PaymentTotalRow({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => Consumer<QuotationProvider>(
|
||||||
|
builder: (context, provider, _) => PaymentSummaryRow(
|
||||||
|
labelFactory: AppLocalizations.of(context)!.total,
|
||||||
|
asset: provider.total,
|
||||||
|
style: Theme.of(context).textTheme.titleMedium!.copyWith(fontWeight: FontWeight.w600),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import 'package:pshared/utils/currency.dart';
|
||||||
|
|
||||||
|
import 'package:pweb/pages/dashboard/payouts/summary/fee.dart';
|
||||||
|
import 'package:pweb/pages/dashboard/payouts/summary/recipient_receives.dart';
|
||||||
|
import 'package:pweb/pages/dashboard/payouts/summary/sent_amount.dart';
|
||||||
|
import 'package:pweb/pages/dashboard/payouts/summary/total.dart';
|
||||||
|
import 'package:pweb/providers/wallets.dart';
|
||||||
|
|
||||||
|
|
||||||
|
class PaymentSummary extends StatelessWidget {
|
||||||
|
final double spacing;
|
||||||
|
|
||||||
|
const PaymentSummary({super.key, required this.spacing});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => Align(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: [
|
||||||
|
PaymentSentAmountRow(currency: currencyStringToCode(context.read<WalletsProvider>().selectedWallet?.tokenSymbol ?? 'USDT')),
|
||||||
|
const PaymentFeeRow(),
|
||||||
|
const PaymentRecipientReceivesRow(),
|
||||||
|
SizedBox(height: spacing),
|
||||||
|
const PaymentTotalRow(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
28
frontend/pweb/lib/pages/dashboard/payouts/widget.dart
Normal file
28
frontend/pweb/lib/pages/dashboard/payouts/widget.dart
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import 'package:pshared/provider/organizations.dart';
|
||||||
|
import 'package:pshared/provider/payment/amount.dart';
|
||||||
|
import 'package:pshared/provider/payment/quotation.dart';
|
||||||
|
|
||||||
|
import 'package:pweb/pages/dashboard/payouts/form.dart';
|
||||||
|
|
||||||
|
|
||||||
|
class PaymentFromWrappingWidget extends StatelessWidget {
|
||||||
|
const PaymentFromWrappingWidget({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => MultiProvider(
|
||||||
|
providers: [
|
||||||
|
ChangeNotifierProvider(
|
||||||
|
create: (_) => PaymentAmountProvider(),
|
||||||
|
),
|
||||||
|
ChangeNotifierProxyProvider2<OrganizationsProvider, PaymentAmountProvider, QuotationProvider>(
|
||||||
|
create: (_) => QuotationProvider(),
|
||||||
|
update: (context, orgnization, payment, provider) => provider!..update(orgnization, payment),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
child: const PaymentFormWidget(),
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -11,7 +11,7 @@ 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';
|
||||||
import 'package:pweb/pages/payment_methods/payment_page/method_selector.dart';
|
import 'package:pweb/pages/payment_methods/payment_page/method_selector.dart';
|
||||||
import 'package:pweb/pages/payment_methods/payment_page/send_button.dart';
|
import 'package:pweb/pages/payment_methods/payment_page/send_button.dart';
|
||||||
import 'package:pweb/pages/dashboard/payouts/payment_form.dart';
|
import 'package:pweb/pages/dashboard/payouts/form.dart';
|
||||||
import 'package:pweb/pages/payment_methods/widgets/payment_info_section.dart';
|
import 'package:pweb/pages/payment_methods/widgets/payment_info_section.dart';
|
||||||
import 'package:pweb/pages/payment_methods/widgets/recipient_section.dart';
|
import 'package:pweb/pages/payment_methods/widgets/recipient_section.dart';
|
||||||
import 'package:pweb/pages/payment_methods/widgets/section_title.dart';
|
import 'package:pweb/pages/payment_methods/widgets/section_title.dart';
|
||||||
|
|||||||
@@ -2,14 +2,14 @@ import 'package:flutter/material.dart';
|
|||||||
|
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
import 'package:pshared/models/payment/methods/type.dart';
|
import 'package:pweb/models/wallet.dart';
|
||||||
import 'package:pshared/provider/recipient/pmethods.dart';
|
import 'package:pweb/providers/wallets.dart';
|
||||||
|
|
||||||
import 'package:pweb/utils/payment/dropdown.dart';
|
import 'package:pweb/utils/payment/dropdown.dart';
|
||||||
|
|
||||||
|
|
||||||
class PaymentMethodSelector extends StatelessWidget {
|
class PaymentMethodSelector extends StatelessWidget {
|
||||||
final ValueChanged<PaymentMethod> onMethodChanged;
|
final ValueChanged<Wallet> onMethodChanged;
|
||||||
|
|
||||||
const PaymentMethodSelector({
|
const PaymentMethodSelector({
|
||||||
super.key,
|
super.key,
|
||||||
@@ -17,9 +17,9 @@ class PaymentMethodSelector extends StatelessWidget {
|
|||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => Consumer<PaymentMethodsProvider>(builder:(context, provider, _) => PaymentMethodDropdown(
|
Widget build(BuildContext context) => Consumer<WalletsProvider>(builder:(context, provider, _) => PaymentMethodDropdown(
|
||||||
methods: provider.methods,
|
methods: provider.wallets,
|
||||||
initialValue: provider.currentObject,
|
initialValue: provider.selectedWallet,
|
||||||
onChanged: onMethodChanged,
|
onChanged: onMethodChanged,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import 'package:pshared/models/recipient/recipient.dart';
|
|||||||
import 'package:pshared/provider/recipient/pmethods.dart';
|
import 'package:pshared/provider/recipient/pmethods.dart';
|
||||||
import 'package:pshared/provider/recipient/provider.dart';
|
import 'package:pshared/provider/recipient/provider.dart';
|
||||||
|
|
||||||
import 'package:pweb/pages/dashboard/payouts/payment_form.dart';
|
import 'package:pweb/pages/dashboard/payouts/widget.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';
|
||||||
import 'package:pweb/pages/payment_methods/payment_page/method_selector.dart';
|
import 'package:pweb/pages/payment_methods/payment_page/method_selector.dart';
|
||||||
@@ -105,7 +105,7 @@ class PaymentPageContent extends StatelessWidget {
|
|||||||
availableTypes: availablePaymentTypes,
|
availableTypes: availablePaymentTypes,
|
||||||
),
|
),
|
||||||
SizedBox(height: dimensions.paddingLarge),
|
SizedBox(height: dimensions.paddingLarge),
|
||||||
const PaymentFormWidget(),
|
const PaymentFromWrappingWidget(),
|
||||||
SizedBox(height: dimensions.paddingXXXLarge),
|
SizedBox(height: dimensions.paddingXXXLarge),
|
||||||
SendButton(onPressed: onSend),
|
SendButton(onPressed: onSend),
|
||||||
SizedBox(height: dimensions.paddingLarge),
|
SizedBox(height: dimensions.paddingLarge),
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import 'package:pshared/utils/currency.dart';
|
||||||
|
|
||||||
import 'package:pweb/models/wallet.dart';
|
import 'package:pweb/models/wallet.dart';
|
||||||
import 'package:pweb/pages/dashboard/buttons/balance/amount.dart';
|
import 'package:pweb/pages/dashboard/buttons/balance/amount.dart';
|
||||||
import 'package:pweb/providers/wallets.dart';
|
import 'package:pweb/providers/wallets.dart';
|
||||||
import 'package:pweb/utils/currency.dart';
|
|
||||||
|
|
||||||
|
|
||||||
class WalletCard extends StatelessWidget {
|
class WalletCard extends StatelessWidget {
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'package:pshared/utils/currency.dart';
|
||||||
|
|
||||||
import 'package:pweb/models/wallet_transaction.dart';
|
import 'package:pweb/models/wallet_transaction.dart';
|
||||||
import 'package:pweb/pages/payout_page/wallet/history/chip.dart';
|
import 'package:pweb/pages/payout_page/wallet/history/chip.dart';
|
||||||
import 'package:pweb/pages/report/table/badge.dart';
|
import 'package:pweb/pages/report/table/badge.dart';
|
||||||
import 'package:pweb/utils/currency.dart';
|
|
||||||
|
|
||||||
import 'package:pweb/generated/i18n/app_localizations.dart';
|
import 'package:pweb/generated/i18n/app_localizations.dart';
|
||||||
|
|
||||||
@@ -66,11 +67,11 @@ class WalletTransactionsTable extends StatelessWidget {
|
|||||||
DataCell(OperationStatusBadge(status: tx.status)),
|
DataCell(OperationStatusBadge(status: tx.status)),
|
||||||
DataCell(TypeChip(type: tx.type)),
|
DataCell(TypeChip(type: tx.type)),
|
||||||
DataCell(Text(
|
DataCell(Text(
|
||||||
'${tx.type.sign}${tx.amount.toStringAsFixed(2)} ${currencyCodeToSymbol(tx.currency)}')),
|
'${tx.type.sign}${amountToString(tx.amount)} ${currencyCodeToSymbol(tx.currency)}')),
|
||||||
DataCell(Text(
|
DataCell(Text(
|
||||||
tx.balanceAfter == null
|
tx.balanceAfter == null
|
||||||
? '-'
|
? '-'
|
||||||
: '${tx.balanceAfter!.toStringAsFixed(2)} ${currencyCodeToSymbol(tx.currency)}',
|
: '${amountToString(tx.balanceAfter!)} ${currencyCodeToSymbol(tx.currency)}',
|
||||||
)),
|
)),
|
||||||
DataCell(Text(tx.counterparty ?? '-')),
|
DataCell(Text(tx.counterparty ?? '-')),
|
||||||
DataCell(Text(
|
DataCell(Text(
|
||||||
|
|||||||
@@ -1,15 +1,18 @@
|
|||||||
// operation_row.dart
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:pshared/models/payment/operation.dart';
|
import 'package:pshared/models/payment/operation.dart';
|
||||||
|
import 'package:pshared/utils/currency.dart';
|
||||||
|
|
||||||
import 'package:pweb/pages/report/table/badge.dart';
|
import 'package:pweb/pages/report/table/badge.dart';
|
||||||
|
|
||||||
|
|
||||||
class OperationRow {
|
class OperationRow {
|
||||||
static DataRow build(OperationItem op, BuildContext context) {
|
static DataRow build(OperationItem op, BuildContext context) {
|
||||||
return DataRow(cells: [
|
return DataRow(cells: [
|
||||||
DataCell(OperationStatusBadge(status: op.status)),
|
DataCell(OperationStatusBadge(status: op.status)),
|
||||||
DataCell(Text(op.fileName ?? '')),
|
DataCell(Text(op.fileName ?? '')),
|
||||||
DataCell(Text('${op.amount.toStringAsFixed(2)} ${op.currency}')),
|
DataCell(Text('${amountToString(op.amount)} ${op.currency}')),
|
||||||
DataCell(Text('${op.toAmount.toStringAsFixed(2)} ${op.toCurrency}')),
|
DataCell(Text('${amountToString(op.toAmount)} ${op.toCurrency}')),
|
||||||
DataCell(Text(op.payId)),
|
DataCell(Text(op.payId)),
|
||||||
DataCell(Text(op.cardNumber ?? '-')),
|
DataCell(Text(op.cardNumber ?? '-')),
|
||||||
DataCell(Text(op.name)),
|
DataCell(Text(op.name)),
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'package:pshared/utils/currency.dart';
|
||||||
|
|
||||||
import 'package:pweb/models/wallet.dart';
|
import 'package:pweb/models/wallet.dart';
|
||||||
import 'package:pweb/pages/wallet_top_up/details.dart';
|
import 'package:pweb/pages/wallet_top_up/details.dart';
|
||||||
import 'package:pweb/pages/wallet_top_up/header.dart';
|
import 'package:pweb/pages/wallet_top_up/header.dart';
|
||||||
import 'package:pweb/pages/wallet_top_up/meta.dart';
|
import 'package:pweb/pages/wallet_top_up/meta.dart';
|
||||||
import 'package:pweb/utils/currency.dart';
|
|
||||||
import 'package:pweb/utils/dimensions.dart';
|
import 'package:pweb/utils/dimensions.dart';
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import 'package:pshared/models/payment/status.dart';
|
import 'package:pshared/models/payment/status.dart';
|
||||||
|
import 'package:pshared/models/currency.dart';
|
||||||
|
|
||||||
import 'package:pweb/models/currency.dart';
|
|
||||||
import 'package:pweb/models/wallet_transaction.dart';
|
import 'package:pweb/models/wallet_transaction.dart';
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,38 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
import 'package:pweb/models/currency.dart';
|
|
||||||
|
|
||||||
|
|
||||||
String currencyCodeToSymbol(Currency currencyCode) {
|
|
||||||
switch (currencyCode) {
|
|
||||||
case Currency.usd:
|
|
||||||
return '\$';
|
|
||||||
case Currency.eur:
|
|
||||||
return '€';
|
|
||||||
case Currency.rub:
|
|
||||||
return '₽';
|
|
||||||
case Currency.usdt:
|
|
||||||
return 'USDT';
|
|
||||||
case Currency.usdc:
|
|
||||||
return 'USDC';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String currencyToString(Currency currencyCode, double amount) {
|
|
||||||
return '${amount.toStringAsFixed(2)} ${currencyCodeToSymbol(currencyCode)}';
|
|
||||||
}
|
|
||||||
|
|
||||||
IconData iconForCurrencyType(Currency currencyCode) {
|
|
||||||
switch (currencyCode) {
|
|
||||||
case Currency.usd:
|
|
||||||
return Icons.currency_exchange;
|
|
||||||
case Currency.eur:
|
|
||||||
return Icons.currency_exchange;
|
|
||||||
case Currency.rub:
|
|
||||||
return Icons.currency_ruble;
|
|
||||||
case Currency.usdt:
|
|
||||||
return Icons.currency_exchange;
|
|
||||||
case Currency.usdc:
|
|
||||||
return Icons.money;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +1,17 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:pshared/models/payment/methods/type.dart';
|
import 'package:pshared/models/payment/type.dart';
|
||||||
|
|
||||||
|
import 'package:pweb/models/wallet.dart';
|
||||||
import 'package:pweb/pages/payment_methods/icon.dart';
|
import 'package:pweb/pages/payment_methods/icon.dart';
|
||||||
|
|
||||||
import 'package:pweb/generated/i18n/app_localizations.dart';
|
import 'package:pweb/generated/i18n/app_localizations.dart';
|
||||||
|
|
||||||
|
|
||||||
class PaymentMethodDropdown extends StatefulWidget {
|
class PaymentMethodDropdown extends StatefulWidget {
|
||||||
final List<PaymentMethod> methods;
|
final List<Wallet> methods;
|
||||||
final ValueChanged<PaymentMethod> onChanged;
|
final ValueChanged<Wallet> onChanged;
|
||||||
final PaymentMethod? initialValue;
|
final Wallet? initialValue;
|
||||||
|
|
||||||
const PaymentMethodDropdown({
|
const PaymentMethodDropdown({
|
||||||
super.key,
|
super.key,
|
||||||
@@ -24,7 +25,7 @@ class PaymentMethodDropdown extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _PaymentMethodDropdownState extends State<PaymentMethodDropdown> {
|
class _PaymentMethodDropdownState extends State<PaymentMethodDropdown> {
|
||||||
late PaymentMethod _selectedMethod;
|
late Wallet _selectedMethod;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@@ -34,7 +35,7 @@ class _PaymentMethodDropdownState extends State<PaymentMethodDropdown> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return DropdownButtonFormField<PaymentMethod>(
|
return DropdownButtonFormField<Wallet>(
|
||||||
dropdownColor: Theme.of(context).colorScheme.onSecondary,
|
dropdownColor: Theme.of(context).colorScheme.onSecondary,
|
||||||
initialValue: _selectedMethod,
|
initialValue: _selectedMethod,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
@@ -42,13 +43,13 @@ class _PaymentMethodDropdownState extends State<PaymentMethodDropdown> {
|
|||||||
border: OutlineInputBorder(borderRadius: BorderRadius.circular(8)),
|
border: OutlineInputBorder(borderRadius: BorderRadius.circular(8)),
|
||||||
),
|
),
|
||||||
items: widget.methods.map((method) {
|
items: widget.methods.map((method) {
|
||||||
return DropdownMenuItem<PaymentMethod>(
|
return DropdownMenuItem<Wallet>(
|
||||||
value: method,
|
value: method,
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Icon(iconForPaymentType(method.type), size: 20),
|
Icon(iconForPaymentType(PaymentType.managedWallet), size: 20),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Text('${method.name}' + (method.description == null ? '' : ' (${method.description!})')),
|
Text(method.name),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user