Frontend first draft
This commit is contained in:
112
frontend/pweb/lib/pages/payment_methods/add/card.dart
Normal file
112
frontend/pweb/lib/pages/payment_methods/add/card.dart
Normal file
@@ -0,0 +1,112 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:flutter_multi_formatter/flutter_multi_formatter.dart';
|
||||
|
||||
import 'package:pshared/models/payment/methods/card.dart';
|
||||
|
||||
import 'package:pweb/utils/text_field_styles.dart';
|
||||
|
||||
import 'package:pweb/generated/i18n/app_localizations.dart';
|
||||
|
||||
|
||||
class CardFormMinimal extends StatefulWidget {
|
||||
final void Function(CardPaymentMethod) onChanged;
|
||||
final CardPaymentMethod? initialData;
|
||||
final bool isEditable;
|
||||
|
||||
const CardFormMinimal({
|
||||
super.key,
|
||||
required this.onChanged,
|
||||
this.initialData,
|
||||
required this.isEditable,
|
||||
});
|
||||
|
||||
@override
|
||||
State<CardFormMinimal> createState() => _CardFormMinimalState();
|
||||
}
|
||||
|
||||
class _CardFormMinimalState extends State<CardFormMinimal> {
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
late TextEditingController _panController;
|
||||
late TextEditingController _firstNameController;
|
||||
late TextEditingController _lastNameController;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_panController = TextEditingController(text: widget.initialData?.pan ?? '');
|
||||
_firstNameController = TextEditingController(text: widget.initialData?.firstName ?? '');
|
||||
_lastNameController = TextEditingController(text: widget.initialData?.lastName ?? '');
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) => _emitIfValid());
|
||||
}
|
||||
|
||||
void _emitIfValid() {
|
||||
if (_formKey.currentState?.validate() ?? false) {
|
||||
widget.onChanged(
|
||||
CardPaymentMethod(
|
||||
pan: _panController.text.replaceAll(' ', ''),
|
||||
firstName: _firstNameController.text,
|
||||
lastName: _lastNameController.text,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(covariant CardFormMinimal oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
if (widget.initialData == null && oldWidget.initialData != null) {
|
||||
_panController.clear();
|
||||
_firstNameController.clear();
|
||||
_lastNameController.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
return Form(
|
||||
key: _formKey,
|
||||
onChanged: _emitIfValid,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
TextFormField(
|
||||
readOnly: !widget.isEditable,
|
||||
controller: _panController,
|
||||
decoration: getInputDecoration(context, l10n.cardNumber, widget.isEditable),
|
||||
style: getTextFieldStyle(context, widget.isEditable),
|
||||
keyboardType: TextInputType.number,
|
||||
inputFormatters: [CreditCardNumberInputFormatter()],
|
||||
validator: (v) => (v == null || v.replaceAll(' ', '').length < 12) ? l10n.enterCardNumber : null,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
TextFormField(
|
||||
readOnly: !widget.isEditable,
|
||||
controller: _firstNameController,
|
||||
decoration: getInputDecoration(context, l10n.firstName, widget.isEditable),
|
||||
style: getTextFieldStyle(context, widget.isEditable),
|
||||
validator: (v) => (v == null || v.isEmpty) ? l10n.enterFirstName : null,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
TextFormField(
|
||||
readOnly: !widget.isEditable,
|
||||
controller: _lastNameController,
|
||||
decoration: getInputDecoration(context, l10n.lastName, widget.isEditable),
|
||||
style: getTextFieldStyle(context, widget.isEditable),
|
||||
validator: (v) => (v == null || v.isEmpty) ? l10n.enterLastName : null,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_panController.dispose();
|
||||
_firstNameController.dispose();
|
||||
_lastNameController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
122
frontend/pweb/lib/pages/payment_methods/add/iban.dart
Normal file
122
frontend/pweb/lib/pages/payment_methods/add/iban.dart
Normal file
@@ -0,0 +1,122 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:pshared/models/payment/methods/iban.dart';
|
||||
|
||||
import 'package:pweb/utils/text_field_styles.dart';
|
||||
|
||||
import 'package:pweb/generated/i18n/app_localizations.dart';
|
||||
|
||||
|
||||
class IbanForm extends StatefulWidget {
|
||||
final void Function(IbanPaymentMethod) onChanged;
|
||||
final IbanPaymentMethod? initialData;
|
||||
final bool isEditable;
|
||||
|
||||
const IbanForm({
|
||||
super.key,
|
||||
required this.onChanged,
|
||||
this.initialData,
|
||||
required this.isEditable,
|
||||
});
|
||||
|
||||
@override
|
||||
State<IbanForm> createState() => _IbanFormState();
|
||||
}
|
||||
|
||||
class _IbanFormState extends State<IbanForm> {
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
late TextEditingController _ibanController;
|
||||
late TextEditingController _accountHolderController;
|
||||
late TextEditingController _bicController;
|
||||
late TextEditingController _bankNameController;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_ibanController = TextEditingController(text: widget.initialData?.iban ?? '');
|
||||
_accountHolderController = TextEditingController(text: widget.initialData?.accountHolder ?? '');
|
||||
_bicController = TextEditingController(text: widget.initialData?.bic ?? '');
|
||||
_bankNameController = TextEditingController(text: widget.initialData?.bankName ?? '');
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) => _emitIfValid());
|
||||
}
|
||||
|
||||
void _emitIfValid() {
|
||||
if (_formKey.currentState?.validate() ?? false) {
|
||||
widget.onChanged(
|
||||
IbanPaymentMethod(
|
||||
iban: _ibanController.text,
|
||||
accountHolder: _accountHolderController.text,
|
||||
bic: _bicController.text,
|
||||
bankName: _bankNameController.text,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(covariant IbanForm oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
if (widget.initialData == null && oldWidget.initialData != null) {
|
||||
_ibanController.clear();
|
||||
_accountHolderController.clear();
|
||||
_bicController.clear();
|
||||
_bankNameController.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
|
||||
return Form(
|
||||
key: _formKey,
|
||||
onChanged: _emitIfValid,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
TextFormField(
|
||||
readOnly: !widget.isEditable,
|
||||
controller: _ibanController,
|
||||
decoration: getInputDecoration(context, l10n.iban, widget.isEditable),
|
||||
style: getTextFieldStyle(context, widget.isEditable),
|
||||
validator: (val) => (val == null || val.isEmpty) ? l10n.enterIban : null,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
TextFormField(
|
||||
readOnly: !widget.isEditable,
|
||||
controller: _accountHolderController,
|
||||
decoration: getInputDecoration(context, l10n.accountHolder, widget.isEditable),
|
||||
style: getTextFieldStyle(context, widget.isEditable),
|
||||
validator: (val) => (val == null || val.isEmpty) ? l10n.enterAccountHolder : null,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
TextFormField(
|
||||
readOnly: !widget.isEditable,
|
||||
controller: _bicController,
|
||||
decoration: getInputDecoration(context, l10n.bic, widget.isEditable),
|
||||
style: getTextFieldStyle(context, widget.isEditable),
|
||||
validator: (val) => (val == null || val.isEmpty) ? l10n.enterBic : null,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
TextFormField(
|
||||
readOnly: !widget.isEditable,
|
||||
controller: _bankNameController,
|
||||
decoration: getInputDecoration(context, l10n.bankName, widget.isEditable),
|
||||
style: getTextFieldStyle(context, widget.isEditable),
|
||||
validator: (val) => (val == null || val.isEmpty) ? l10n.enterBankName : null,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_ibanController.dispose();
|
||||
_accountHolderController.dispose();
|
||||
_bicController.dispose();
|
||||
_bankNameController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:pshared/models/payment/type.dart';
|
||||
|
||||
import 'package:pweb/generated/i18n/app_localizations.dart';
|
||||
import 'package:pweb/utils/payment/label.dart';
|
||||
|
||||
|
||||
class PaymentMethodTypeSelector extends StatelessWidget {
|
||||
final PaymentType? value;
|
||||
final ValueChanged<PaymentType?> onChanged;
|
||||
|
||||
const PaymentMethodTypeSelector({
|
||||
super.key,
|
||||
required this.value,
|
||||
required this.onChanged,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
|
||||
return DropdownButtonFormField<PaymentType>(
|
||||
value: value,
|
||||
decoration: InputDecoration(labelText: l10n.paymentType),
|
||||
items: PaymentType.values.map((type) {
|
||||
final label = getPaymentTypeLabel(context, type);
|
||||
return DropdownMenuItem(value: type, child: Text(label));
|
||||
}).toList(),
|
||||
onChanged: onChanged,
|
||||
validator: (val) => val == null ? l10n.selectPaymentType : null,
|
||||
);
|
||||
}
|
||||
}
|
||||
162
frontend/pweb/lib/pages/payment_methods/add/russian_bank.dart
Normal file
162
frontend/pweb/lib/pages/payment_methods/add/russian_bank.dart
Normal file
@@ -0,0 +1,162 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:pshared/models/payment/methods/russian_bank.dart';
|
||||
|
||||
import 'package:pweb/generated/i18n/app_localizations.dart';
|
||||
import 'package:pweb/utils/text_field_styles.dart';
|
||||
|
||||
|
||||
class RussianBankForm extends StatefulWidget {
|
||||
final void Function(RussianBankAccountPaymentMethod) onChanged;
|
||||
final RussianBankAccountPaymentMethod? initialData;
|
||||
final bool isEditable;
|
||||
|
||||
const RussianBankForm({
|
||||
super.key,
|
||||
required this.onChanged,
|
||||
this.initialData,
|
||||
required this.isEditable,
|
||||
});
|
||||
|
||||
@override
|
||||
State<RussianBankForm> createState() => _RussianBankFormState();
|
||||
}
|
||||
|
||||
class _RussianBankFormState extends State<RussianBankForm> {
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
|
||||
late final TextEditingController _recipientNameController;
|
||||
late final TextEditingController _innController;
|
||||
late final TextEditingController _kppController;
|
||||
late final TextEditingController _bankNameController;
|
||||
late final TextEditingController _bikController;
|
||||
late final TextEditingController _accountNumberController;
|
||||
late final TextEditingController _correspondentAccountController;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_recipientNameController = TextEditingController(text: widget.initialData?.recipientName ?? '');
|
||||
_innController = TextEditingController(text: widget.initialData?.inn ?? '');
|
||||
_kppController = TextEditingController(text: widget.initialData?.kpp ?? '');
|
||||
_bankNameController = TextEditingController(text: widget.initialData?.bankName ?? '');
|
||||
_bikController = TextEditingController(text: widget.initialData?.bik ?? '');
|
||||
_accountNumberController = TextEditingController(text: widget.initialData?.accountNumber ?? '');
|
||||
_correspondentAccountController = TextEditingController(text: widget.initialData?.correspondentAccount ?? '');
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) => _emitIfValid());
|
||||
}
|
||||
|
||||
void _emitIfValid() {
|
||||
if (_formKey.currentState?.validate() ?? false) {
|
||||
widget.onChanged(
|
||||
RussianBankAccountPaymentMethod(
|
||||
recipientName: _recipientNameController.text,
|
||||
inn: _innController.text,
|
||||
kpp: _kppController.text,
|
||||
bankName: _bankNameController.text,
|
||||
bik: _bikController.text,
|
||||
accountNumber: _accountNumberController.text,
|
||||
correspondentAccount: _correspondentAccountController.text,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(covariant RussianBankForm oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
if (widget.initialData == null && oldWidget.initialData != null) {
|
||||
_recipientNameController.clear();
|
||||
_innController.clear();
|
||||
_kppController.clear();
|
||||
_bankNameController.clear();
|
||||
_bikController.clear();
|
||||
_accountNumberController.clear();
|
||||
_correspondentAccountController.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
|
||||
return Form(
|
||||
key: _formKey,
|
||||
onChanged: _emitIfValid,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
TextFormField(
|
||||
readOnly: !widget.isEditable,
|
||||
controller: _recipientNameController,
|
||||
decoration: getInputDecoration(context, l10n.recipientName, widget.isEditable),
|
||||
style: getTextFieldStyle(context, widget.isEditable),
|
||||
validator: (val) => (val == null || val.isEmpty) ? l10n.enterRecipientName : null,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
TextFormField(
|
||||
readOnly: !widget.isEditable,
|
||||
controller: _innController,
|
||||
decoration: getInputDecoration(context, l10n.inn, widget.isEditable),
|
||||
style: getTextFieldStyle(context, widget.isEditable),
|
||||
validator: (val) => (val == null || val.isEmpty) ? l10n.enterInn : null,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
TextFormField(
|
||||
readOnly: !widget.isEditable,
|
||||
controller: _kppController,
|
||||
decoration: getInputDecoration(context, l10n.kpp, widget.isEditable),
|
||||
style: getTextFieldStyle(context, widget.isEditable),
|
||||
validator: (val) => (val == null || val.isEmpty) ? l10n.enterKpp : null,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
TextFormField(
|
||||
readOnly: !widget.isEditable,
|
||||
controller: _bankNameController,
|
||||
decoration: getInputDecoration(context, l10n.bankName, widget.isEditable),
|
||||
style: getTextFieldStyle(context, widget.isEditable),
|
||||
validator: (val) => (val == null || val.isEmpty) ? l10n.enterBankName : null,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
TextFormField(
|
||||
readOnly: !widget.isEditable,
|
||||
controller: _bikController,
|
||||
decoration: getInputDecoration(context, l10n.bik, widget.isEditable),
|
||||
style: getTextFieldStyle(context, widget.isEditable),
|
||||
validator: (val) => (val == null || val.isEmpty) ? l10n.enterBik : null,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
TextFormField(
|
||||
readOnly: !widget.isEditable,
|
||||
controller: _accountNumberController,
|
||||
decoration: getInputDecoration(context, l10n.accountNumber, widget.isEditable),
|
||||
style: getTextFieldStyle(context, widget.isEditable),
|
||||
validator: (val) => (val == null || val.isEmpty) ? l10n.enterAccountNumber : null,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
TextFormField(
|
||||
readOnly: !widget.isEditable,
|
||||
controller: _correspondentAccountController,
|
||||
decoration: getInputDecoration(context, l10n.correspondentAccount, widget.isEditable),
|
||||
style: getTextFieldStyle(context, widget.isEditable),
|
||||
validator: (val) => (val == null || val.isEmpty) ? l10n.enterCorrespondentAccount : null,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_recipientNameController.dispose();
|
||||
_innController.dispose();
|
||||
_kppController.dispose();
|
||||
_bankNameController.dispose();
|
||||
_bikController.dispose();
|
||||
_accountNumberController.dispose();
|
||||
_correspondentAccountController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
62
frontend/pweb/lib/pages/payment_methods/add/wallet.dart
Normal file
62
frontend/pweb/lib/pages/payment_methods/add/wallet.dart
Normal file
@@ -0,0 +1,62 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:pshared/models/payment/methods/wallet.dart';
|
||||
|
||||
import 'package:pweb/generated/i18n/app_localizations.dart';
|
||||
import 'package:pweb/utils/text_field_styles.dart';
|
||||
|
||||
|
||||
class WalletForm extends StatefulWidget {
|
||||
final void Function(WalletPaymentMethod) onChanged;
|
||||
final WalletPaymentMethod? initialData;
|
||||
final bool isEditable;
|
||||
|
||||
const WalletForm({
|
||||
super.key,
|
||||
required this.onChanged,
|
||||
this.initialData,
|
||||
required this.isEditable,
|
||||
});
|
||||
|
||||
@override
|
||||
State<WalletForm> createState() => _WalletFormState();
|
||||
}
|
||||
|
||||
class _WalletFormState extends State<WalletForm> {
|
||||
late TextEditingController _walletIdController;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_walletIdController = TextEditingController(text: widget.initialData?.walletId);
|
||||
}
|
||||
|
||||
void _emit() {
|
||||
if (_walletIdController.text.isNotEmpty) {
|
||||
widget.onChanged(WalletPaymentMethod(walletId: _walletIdController.text));
|
||||
} else {
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(covariant WalletForm oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
if (widget.initialData == null && oldWidget.initialData != null) {
|
||||
_walletIdController.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
|
||||
return TextFormField(
|
||||
readOnly: !widget.isEditable,
|
||||
controller: _walletIdController,
|
||||
decoration: getInputDecoration(context, l10n.walletId, widget.isEditable),
|
||||
style: getTextFieldStyle(context, widget.isEditable),
|
||||
onChanged: (_) => _emit(),
|
||||
validator: (val) => (val?.isEmpty ?? true) ? l10n.enterWalletId : null,
|
||||
);
|
||||
}
|
||||
}
|
||||
76
frontend/pweb/lib/pages/payment_methods/add/widget.dart
Normal file
76
frontend/pweb/lib/pages/payment_methods/add/widget.dart
Normal file
@@ -0,0 +1,76 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:pshared/models/payment/type.dart';
|
||||
|
||||
import 'package:pweb/pages/payment_methods/add/method_selector.dart';
|
||||
import 'package:pweb/pages/payment_methods/form.dart';
|
||||
|
||||
import 'package:pweb/generated/i18n/app_localizations.dart';
|
||||
|
||||
|
||||
class AddPaymentMethodDialog extends StatefulWidget {
|
||||
const AddPaymentMethodDialog({super.key});
|
||||
|
||||
@override
|
||||
State<AddPaymentMethodDialog> createState() => _AddPaymentMethodDialogState();
|
||||
}
|
||||
|
||||
class _AddPaymentMethodDialogState extends State<AddPaymentMethodDialog> {
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
PaymentType? _selectedType;
|
||||
|
||||
// Holds current result from the selected form
|
||||
Object? _currentMethod;
|
||||
|
||||
void _submit() {
|
||||
if (_formKey.currentState!.validate()) {
|
||||
_formKey.currentState!.save();
|
||||
|
||||
if (_currentMethod case final Object method) {
|
||||
Navigator.of(context).pop(method);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
|
||||
return AlertDialog(
|
||||
title: Text(l10n.addPaymentMethod),
|
||||
content: Form(
|
||||
key: _formKey,
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
PaymentMethodTypeSelector(
|
||||
value: _selectedType,
|
||||
onChanged: (val) => setState(() {
|
||||
_selectedType = val;
|
||||
_currentMethod = null;
|
||||
}),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
if (_selectedType != null)
|
||||
PaymentMethodForm(
|
||||
selectedType: _selectedType,
|
||||
onChanged: (val) => _currentMethod = val,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: Text(l10n.cancel),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: _submit,
|
||||
child: Text(l10n.add),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user