Add ‘Configure gateways’ button to Settings > Online Payments
This commit is contained in:
parent
8b03373297
commit
0810ab02d7
|
|
@ -291,19 +291,6 @@ const kAgeGroups = {
|
|||
kAgeGroup120: 120,
|
||||
};
|
||||
|
||||
/*
|
||||
const String kEmailTemplateInvoice = 'invoice_email';
|
||||
const String kEmailTemplateQuote = 'quote_email';
|
||||
const String kEmailTemplatePayment = 'payment_email';
|
||||
const String kEmailTemplateReminder1 = 'first_reminder';
|
||||
const String kEmailTemplateReminder2 = 'second_reminder';
|
||||
const String kEmailTemplateReminder3 = 'third_reminder';
|
||||
const String kEmailTemplateReminder4 = 'endless_reminder';
|
||||
const String kEmailTemplateCustom1 = 'first_custom';
|
||||
const String kEmailTemplateCustom2 = 'second_custom';
|
||||
const String kEmailTemplateCustom3 = 'third_custom';
|
||||
*/
|
||||
|
||||
const String kReminderScheduleAfterInvoiceDate = 'after_invoice_date';
|
||||
const String kReminderScheduleBeforeDueDate = 'before_due_date';
|
||||
const String kReminderScheduleAfterDueDate = 'after_due_date';
|
||||
|
|
@ -315,8 +302,9 @@ const String kSettingsPaymentTermEdit = 'payment_term_edit';
|
|||
const String kSettingsUserDetails = 'user_details';
|
||||
const String kSettingsLocalization = 'localization';
|
||||
const String kSettingsOnlinePayments = 'online_payments';
|
||||
const String kSettingsOnlinePaymentsView = 'online_payments_view';
|
||||
const String kSettingsOnlinePaymentsEdit = 'online_payments_edit';
|
||||
const String kSettingsCompanyGateways = 'company_gateways';
|
||||
const String kSettingsCompanyGatewaysView = 'company_gateways_view';
|
||||
const String kSettingsCompanyGatewaysEdit = 'company_gateways_edit';
|
||||
const String kSettingsTaxSettings = 'tax_settings';
|
||||
const String kSettingsTaxRates = 'tax_settings_rates';
|
||||
const String kSettingsTaxRatesView = 'tax_settings_rates_view';
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ import 'package:invoiceninja_flutter/ui/reports/reports_screen.dart';
|
|||
import 'package:invoiceninja_flutter/ui/reports/reports_screen_vm.dart';
|
||||
import 'package:invoiceninja_flutter/ui/settings/account_management_vm.dart';
|
||||
import 'package:invoiceninja_flutter/ui/settings/expense_settings_vm.dart';
|
||||
import 'package:invoiceninja_flutter/ui/settings/online_payments_vm.dart';
|
||||
import 'package:invoiceninja_flutter/ui/settings/settings_screen_vm.dart';
|
||||
import 'package:invoiceninja_flutter/ui/settings/tax_settings_vm.dart';
|
||||
import 'package:invoiceninja_flutter/ui/tax_rate/edit/tax_rate_edit_vm.dart';
|
||||
|
|
@ -292,7 +293,6 @@ class InvoiceNinjaAppState extends State<InvoiceNinjaApp> {
|
|||
RecurringInvoiceViewScreen(),
|
||||
RecurringInvoiceEditScreen.route: (context) =>
|
||||
RecurringInvoiceEditScreen(),
|
||||
|
||||
WebhookScreen.route: (context) => WebhookScreenBuilder(),
|
||||
WebhookViewScreen.route: (context) => WebhookViewScreen(),
|
||||
WebhookEditScreen.route: (context) => WebhookEditScreen(),
|
||||
|
|
@ -323,6 +323,8 @@ class InvoiceNinjaAppState extends State<InvoiceNinjaApp> {
|
|||
CompanyDetailsScreen(),
|
||||
UserDetailsScreen.route: (context) => UserDetailsScreen(),
|
||||
LocalizationScreen.route: (context) => LocalizationScreen(),
|
||||
OnlinePaymentsScreen.route: (context) =>
|
||||
OnlinePaymentsScreen(),
|
||||
CompanyGatewayScreen.route: (context) =>
|
||||
CompanyGatewayScreenBuilder(),
|
||||
CompanyGatewayViewScreen.route: (context) =>
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ import 'package:invoiceninja_flutter/ui/reports/reports_screen.dart';
|
|||
import 'package:invoiceninja_flutter/ui/reports/reports_screen_vm.dart';
|
||||
import 'package:invoiceninja_flutter/ui/settings/account_management_vm.dart';
|
||||
import 'package:invoiceninja_flutter/ui/settings/expense_settings_vm.dart';
|
||||
import 'package:invoiceninja_flutter/ui/settings/online_payments_vm.dart';
|
||||
import 'package:invoiceninja_flutter/ui/settings/settings_screen_vm.dart';
|
||||
import 'package:invoiceninja_flutter/ui/settings/tax_settings_vm.dart';
|
||||
import 'package:invoiceninja_flutter/ui/token/edit/token_edit_vm.dart';
|
||||
|
|
@ -380,12 +381,15 @@ class SettingsScreens extends StatelessWidget {
|
|||
screen = LocalizationScreen();
|
||||
break;
|
||||
case kSettingsOnlinePayments:
|
||||
screen = OnlinePaymentsScreen();
|
||||
break;
|
||||
case kSettingsCompanyGateways:
|
||||
screen = CompanyGatewayScreenBuilder();
|
||||
break;
|
||||
case kSettingsOnlinePaymentsView:
|
||||
case kSettingsCompanyGatewaysView:
|
||||
screen = CompanyGatewayViewScreen();
|
||||
break;
|
||||
case kSettingsOnlinePaymentsEdit:
|
||||
case kSettingsCompanyGatewaysEdit:
|
||||
screen = CompanyGatewayEditScreen();
|
||||
break;
|
||||
case kSettingsTaxSettings:
|
||||
|
|
|
|||
|
|
@ -1,18 +1,10 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_redux/flutter_redux.dart';
|
||||
import 'package:invoiceninja_flutter/data/models/company_model.dart';
|
||||
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
|
||||
import 'package:invoiceninja_flutter/ui/app/form_card.dart';
|
||||
import 'package:invoiceninja_flutter/ui/app/forms/app_dropdown_button.dart';
|
||||
import 'package:invoiceninja_flutter/ui/app/forms/app_form.dart';
|
||||
import 'package:invoiceninja_flutter/ui/app/forms/bool_dropdown_button.dart';
|
||||
import 'package:invoiceninja_flutter/ui/app/forms/decorated_form_field.dart';
|
||||
import 'package:invoiceninja_flutter/ui/app/loading_indicator.dart';
|
||||
import 'package:invoiceninja_flutter/ui/company_gateway/company_gateway_list_item.dart';
|
||||
import 'package:invoiceninja_flutter/ui/company_gateway/company_gateway_list_vm.dart';
|
||||
import 'package:invoiceninja_flutter/utils/formatting.dart';
|
||||
import 'package:invoiceninja_flutter/utils/localization.dart';
|
||||
|
||||
class CompanyGatewayList extends StatelessWidget {
|
||||
const CompanyGatewayList({
|
||||
|
|
@ -29,19 +21,10 @@ class CompanyGatewayList extends StatelessWidget {
|
|||
final listUIState = state.uiState.companyGatewayUIState.listUIState;
|
||||
final isInMultiselect = listUIState.isInMultiselect();
|
||||
|
||||
return ListView(
|
||||
shrinkWrap: true,
|
||||
children: <Widget>[
|
||||
_OnlinePaymentForm(
|
||||
viewModel: viewModel,
|
||||
key: ValueKey('__settings_${state.settingsUIState.updatedAt}__'),
|
||||
),
|
||||
!viewModel.state.isLoaded && viewModel.companyGatewayList.isEmpty
|
||||
return !viewModel.state.isLoaded && viewModel.companyGatewayList.isEmpty
|
||||
? LoadingIndicator()
|
||||
: RefreshIndicator(
|
||||
onRefresh: () => viewModel.onRefreshed(context),
|
||||
child: SizedBox(
|
||||
height: (viewModel.companyGatewayList.length * 80.0) + 100,
|
||||
child: ReorderableListView(
|
||||
onReorder: (oldIndex, newIndex) {
|
||||
// https://stackoverflow.com/a/54164333/497368
|
||||
|
|
@ -55,8 +38,7 @@ class CompanyGatewayList extends StatelessWidget {
|
|||
|
||||
viewModel.onSortChanged(oldIndex, newIndex);
|
||||
},
|
||||
children:
|
||||
viewModel.companyGatewayList.map((companyGatewayId) {
|
||||
children: viewModel.companyGatewayList.map((companyGatewayId) {
|
||||
final companyGateway =
|
||||
viewModel.companyGatewayMap[companyGatewayId];
|
||||
return CompanyGatewayListItem(
|
||||
|
|
@ -64,155 +46,13 @@ class CompanyGatewayList extends StatelessWidget {
|
|||
user: state.userCompany.user,
|
||||
filter: viewModel.filter,
|
||||
companyGateway: companyGateway,
|
||||
onRemovePressed: viewModel
|
||||
.state.settingsUIState.isFiltered
|
||||
? () =>
|
||||
viewModel.onRemovePressed(companyGatewayId)
|
||||
onRemovePressed: viewModel.state.settingsUIState.isFiltered
|
||||
? () => viewModel.onRemovePressed(companyGatewayId)
|
||||
: null,
|
||||
isChecked: isInMultiselect &&
|
||||
listUIState.isSelected(companyGateway.id));
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _OnlinePaymentForm extends StatefulWidget {
|
||||
const _OnlinePaymentForm({Key key, @required this.viewModel})
|
||||
: super(key: key);
|
||||
|
||||
final CompanyGatewayListVM viewModel;
|
||||
|
||||
@override
|
||||
__OnlinePaymentFormState createState() => __OnlinePaymentFormState();
|
||||
}
|
||||
|
||||
class __OnlinePaymentFormState extends State<_OnlinePaymentForm> {
|
||||
static final GlobalKey<FormState> _formKey =
|
||||
GlobalKey<FormState>(debugLabel: '_companyGatewayList');
|
||||
final FocusScopeNode _focusNode = FocusScopeNode();
|
||||
|
||||
//bool _autoValidate = false;
|
||||
|
||||
final _minimumAmountController = TextEditingController();
|
||||
|
||||
List<TextEditingController> _controllers = [];
|
||||
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
_controllers = [
|
||||
_minimumAmountController,
|
||||
];
|
||||
|
||||
_controllers
|
||||
.forEach((dynamic controller) => controller.removeListener(_onChanged));
|
||||
|
||||
_minimumAmountController.text = formatNumber(
|
||||
widget.viewModel.settings.clientPortalUnderPaymentMinimum, context,
|
||||
formatNumberType: FormatNumberType.inputMoney);
|
||||
|
||||
_controllers
|
||||
.forEach((dynamic controller) => controller.addListener(_onChanged));
|
||||
|
||||
super.didChangeDependencies();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controllers.forEach((dynamic controller) {
|
||||
controller.removeListener(_onChanged);
|
||||
controller.dispose();
|
||||
});
|
||||
_focusNode.dispose();
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _onChanged() {
|
||||
final viewModel = widget.viewModel;
|
||||
final settings = viewModel.settings.rebuild((b) => b
|
||||
..clientPortalUnderPaymentMinimum =
|
||||
parseDouble(_minimumAmountController.text));
|
||||
if (settings != viewModel.settings) {
|
||||
viewModel.onSettingsChanged(settings);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final localization = AppLocalization.of(context);
|
||||
final viewModel = widget.viewModel;
|
||||
final company = viewModel.state.settingsUIState.company;
|
||||
final settings = viewModel.settings;
|
||||
|
||||
return AppForm(
|
||||
formKey: _formKey,
|
||||
focusNode: _focusNode,
|
||||
child: FormCard(children: [
|
||||
AppDropdownButton<String>(
|
||||
labelText: localization.autoBillOn,
|
||||
value: settings.autoBillDate,
|
||||
onChanged: (dynamic value) => viewModel.onSettingsChanged(
|
||||
settings.rebuild((b) => b..autoBillDate = value)),
|
||||
items: [
|
||||
DropdownMenuItem(
|
||||
child: Text(localization.sendDate),
|
||||
value: SettingsEntity.AUTO_BILL_ON_SEND_DATE,
|
||||
),
|
||||
DropdownMenuItem(
|
||||
child: Text(localization.dueDate),
|
||||
value: SettingsEntity.AUTO_BILL_ON_DUE_DATE,
|
||||
),
|
||||
],
|
||||
),
|
||||
AppDropdownButton<String>(
|
||||
labelText: localization.useAvailableCredits,
|
||||
value: company.useCreditsPayment,
|
||||
onChanged: (dynamic value) {
|
||||
viewModel.onCompanyChanged(
|
||||
company.rebuild((b) => b..useCreditsPayment = value));
|
||||
},
|
||||
items: [
|
||||
DropdownMenuItem(
|
||||
child: Text(localization.always),
|
||||
value: CompanyEntity.USE_CREDITS_ALWAYS,
|
||||
),
|
||||
DropdownMenuItem(
|
||||
child: Text(localization.showOption),
|
||||
value: CompanyEntity.USE_CREDITS_OPTION,
|
||||
),
|
||||
DropdownMenuItem(
|
||||
child: Text(localization.off),
|
||||
value: CompanyEntity.USE_CREDITS_OFF,
|
||||
),
|
||||
]),
|
||||
SizedBox(height: 16),
|
||||
BoolDropdownButton(
|
||||
label: localization.allowOverPayment,
|
||||
value: settings.clientPortalAllowOverPayment,
|
||||
helpLabel: localization.allowOverPaymentHelp,
|
||||
onChanged: (value) => viewModel.onSettingsChanged(
|
||||
settings.rebuild((b) => b..clientPortalAllowOverPayment = value)),
|
||||
),
|
||||
BoolDropdownButton(
|
||||
label: localization.allowUnderPayment,
|
||||
value: settings.clientPortalAllowUnderPayment,
|
||||
helpLabel: localization.allowUnderPaymentHelp,
|
||||
onChanged: (value) => viewModel.onSettingsChanged(settings
|
||||
.rebuild((b) => b..clientPortalAllowUnderPayment = value)),
|
||||
),
|
||||
if (settings.clientPortalAllowUnderPayment == true)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 16),
|
||||
child: DecoratedFormField(
|
||||
label: localization.minimumUnderPaymentAmount,
|
||||
controller: _minimumAmountController,
|
||||
),
|
||||
),
|
||||
]),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import 'dart:async';
|
||||
import 'package:invoiceninja_flutter/data/models/company_gateway_model.dart';
|
||||
import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
|
||||
import 'package:invoiceninja_flutter/redux/company/company_actions.dart';
|
||||
import 'package:invoiceninja_flutter/redux/settings/settings_actions.dart';
|
||||
import 'package:redux/redux.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
|
@ -45,9 +44,6 @@ class CompanyGatewayListVM {
|
|||
@required this.onRefreshed,
|
||||
@required this.onSortChanged,
|
||||
@required this.onRemovePressed,
|
||||
@required this.onSettingsChanged,
|
||||
@required this.settings,
|
||||
@required this.onCompanyChanged,
|
||||
});
|
||||
|
||||
static CompanyGatewayListVM fromStore(Store<AppState> store) {
|
||||
|
|
@ -81,9 +77,6 @@ class CompanyGatewayListVM {
|
|||
state: state,
|
||||
listState: state.companyGatewayListState,
|
||||
companyGatewayList: gatewayIds,
|
||||
settings: state.uiState.settingsUIState.settings,
|
||||
onCompanyChanged: (company) =>
|
||||
store.dispatch(UpdateCompany(company: company)),
|
||||
companyGatewayMap: state.companyGatewayState.map,
|
||||
filter: state.companyGatewayUIState.listUIState.filter,
|
||||
onCompanyGatewayTap: (context, companyGateway) {
|
||||
|
|
@ -111,8 +104,6 @@ class CompanyGatewayListVM {
|
|||
.rebuild((b) => b..companyGatewayIds = gatewayIds.join(','));
|
||||
store.dispatch(UpdateSettings(settings: settings));
|
||||
},
|
||||
onSettingsChanged: (settings) =>
|
||||
store.dispatch(UpdateSettings(settings: settings)),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -125,7 +116,4 @@ class CompanyGatewayListVM {
|
|||
final Function(BuildContext) onRefreshed;
|
||||
final Function(int, int) onSortChanged;
|
||||
final Function(String) onRemovePressed;
|
||||
final SettingsEntity settings;
|
||||
final Function(SettingsEntity) onSettingsChanged;
|
||||
final Function(CompanyEntity) onCompanyChanged;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ class CompanyGatewayScreen extends StatelessWidget {
|
|||
@required this.viewModel,
|
||||
}) : super(key: key);
|
||||
|
||||
static const String route = '/$kSettings/$kSettingsOnlinePayments';
|
||||
static const String route = '/$kSettings/$kSettingsCompanyGateways';
|
||||
|
||||
final CompanyGatewayScreenVM viewModel;
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import 'package:invoiceninja_flutter/redux/app/app_state.dart';
|
|||
|
||||
class CompanyGatewayEditScreen extends StatelessWidget {
|
||||
const CompanyGatewayEditScreen({Key key}) : super(key: key);
|
||||
static const String route = '/$kSettings/$kSettingsOnlinePaymentsEdit';
|
||||
static const String route = '/$kSettings/$kSettingsCompanyGatewaysEdit';
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ class CompanyGatewayViewScreen extends StatelessWidget {
|
|||
}) : super(key: key);
|
||||
final bool isFilter;
|
||||
|
||||
static const String route = '/$kSettings/$kSettingsOnlinePaymentsView';
|
||||
static const String route = '/$kSettings/$kSettingsCompanyGatewaysView';
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,163 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:invoiceninja_flutter/data/models/company_model.dart';
|
||||
import 'package:invoiceninja_flutter/ui/app/buttons/elevated_button.dart';
|
||||
import 'package:invoiceninja_flutter/ui/app/form_card.dart';
|
||||
import 'package:invoiceninja_flutter/ui/app/forms/app_dropdown_button.dart';
|
||||
import 'package:invoiceninja_flutter/ui/app/forms/app_form.dart';
|
||||
import 'package:invoiceninja_flutter/ui/app/forms/bool_dropdown_button.dart';
|
||||
import 'package:invoiceninja_flutter/ui/app/forms/decorated_form_field.dart';
|
||||
import 'package:invoiceninja_flutter/ui/settings/online_payments_vm.dart';
|
||||
import 'package:invoiceninja_flutter/ui/app/edit_scaffold.dart';
|
||||
import 'package:invoiceninja_flutter/utils/formatting.dart';
|
||||
import 'package:invoiceninja_flutter/utils/localization.dart';
|
||||
|
||||
class OnlinePayments extends StatefulWidget {
|
||||
const OnlinePayments({
|
||||
Key key,
|
||||
@required this.viewModel,
|
||||
}) : super(key: key);
|
||||
|
||||
final OnlinePaymentsVM viewModel;
|
||||
|
||||
@override
|
||||
_OnlinePaymentsState createState() => _OnlinePaymentsState();
|
||||
}
|
||||
|
||||
class _OnlinePaymentsState extends State<OnlinePayments> {
|
||||
static final GlobalKey<FormState> _formKey =
|
||||
GlobalKey<FormState>(debugLabel: '_onlinePayments');
|
||||
FocusScopeNode _focusNode;
|
||||
final _minimumAmountController = TextEditingController();
|
||||
List<TextEditingController> _controllers = [];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_focusNode = FocusScopeNode();
|
||||
}
|
||||
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
_controllers = [
|
||||
_minimumAmountController,
|
||||
];
|
||||
|
||||
_controllers
|
||||
.forEach((dynamic controller) => controller.removeListener(_onChanged));
|
||||
|
||||
_minimumAmountController.text = formatNumber(
|
||||
widget.viewModel.settings.clientPortalUnderPaymentMinimum, context,
|
||||
formatNumberType: FormatNumberType.inputMoney);
|
||||
|
||||
_controllers
|
||||
.forEach((dynamic controller) => controller.addListener(_onChanged));
|
||||
|
||||
super.didChangeDependencies();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_focusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _onChanged() {
|
||||
final viewModel = widget.viewModel;
|
||||
final settings = viewModel.settings.rebuild((b) => b
|
||||
..clientPortalUnderPaymentMinimum =
|
||||
parseDouble(_minimumAmountController.text));
|
||||
if (settings != viewModel.settings) {
|
||||
viewModel.onSettingsChanged(settings);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final localization = AppLocalization.of(context);
|
||||
final viewModel = widget.viewModel;
|
||||
final company = viewModel.company;
|
||||
final settings = viewModel.settings;
|
||||
|
||||
return EditScaffold(
|
||||
title: localization.onlinePayments,
|
||||
onSavePressed: viewModel.onSavePressed,
|
||||
body: AppForm(
|
||||
formKey: _formKey,
|
||||
focusNode: _focusNode,
|
||||
children: <Widget>[
|
||||
FormCard(children: <Widget>[
|
||||
AppDropdownButton<String>(
|
||||
labelText: localization.autoBillOn,
|
||||
value: settings.autoBillDate,
|
||||
onChanged: (dynamic value) => viewModel.onSettingsChanged(
|
||||
settings.rebuild((b) => b..autoBillDate = value)),
|
||||
items: [
|
||||
DropdownMenuItem(
|
||||
child: Text(localization.sendDate),
|
||||
value: SettingsEntity.AUTO_BILL_ON_SEND_DATE,
|
||||
),
|
||||
DropdownMenuItem(
|
||||
child: Text(localization.dueDate),
|
||||
value: SettingsEntity.AUTO_BILL_ON_DUE_DATE,
|
||||
),
|
||||
],
|
||||
),
|
||||
AppDropdownButton<String>(
|
||||
labelText: localization.useAvailableCredits,
|
||||
value: company.useCreditsPayment,
|
||||
onChanged: (dynamic value) {
|
||||
viewModel.onCompanyChanged(
|
||||
company.rebuild((b) => b..useCreditsPayment = value));
|
||||
},
|
||||
items: [
|
||||
DropdownMenuItem(
|
||||
child: Text(localization.always),
|
||||
value: CompanyEntity.USE_CREDITS_ALWAYS,
|
||||
),
|
||||
DropdownMenuItem(
|
||||
child: Text(localization.showOption),
|
||||
value: CompanyEntity.USE_CREDITS_OPTION,
|
||||
),
|
||||
DropdownMenuItem(
|
||||
child: Text(localization.off),
|
||||
value: CompanyEntity.USE_CREDITS_OFF,
|
||||
),
|
||||
]),
|
||||
SizedBox(height: 16),
|
||||
BoolDropdownButton(
|
||||
label: localization.allowOverPayment,
|
||||
value: settings.clientPortalAllowOverPayment,
|
||||
helpLabel: localization.allowOverPaymentHelp,
|
||||
onChanged: (value) => viewModel.onSettingsChanged(settings
|
||||
.rebuild((b) => b..clientPortalAllowOverPayment = value)),
|
||||
),
|
||||
BoolDropdownButton(
|
||||
label: localization.allowUnderPayment,
|
||||
value: settings.clientPortalAllowUnderPayment,
|
||||
helpLabel: localization.allowUnderPaymentHelp,
|
||||
onChanged: (value) => viewModel.onSettingsChanged(settings
|
||||
.rebuild((b) => b..clientPortalAllowUnderPayment = value)),
|
||||
),
|
||||
if (settings.clientPortalAllowUnderPayment == true)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 16),
|
||||
child: DecoratedFormField(
|
||||
label: localization.minimumUnderPaymentAmount,
|
||||
controller: _minimumAmountController,
|
||||
),
|
||||
),
|
||||
]),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: AppButton(
|
||||
iconData: Icons.settings,
|
||||
label: localization.configureGateways.toUpperCase(),
|
||||
onPressed: () => viewModel.onConfigureGatewaysPressed(context),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_redux/flutter_redux.dart';
|
||||
import 'package:invoiceninja_flutter/constants.dart';
|
||||
import 'package:invoiceninja_flutter/data/models/client_model.dart';
|
||||
import 'package:invoiceninja_flutter/data/models/company_model.dart';
|
||||
import 'package:invoiceninja_flutter/data/models/entities.dart';
|
||||
import 'package:invoiceninja_flutter/data/models/group_model.dart';
|
||||
import 'package:invoiceninja_flutter/redux/client/client_actions.dart';
|
||||
import 'package:invoiceninja_flutter/redux/company/company_actions.dart';
|
||||
import 'package:invoiceninja_flutter/redux/group/group_actions.dart';
|
||||
import 'package:invoiceninja_flutter/redux/settings/settings_actions.dart';
|
||||
import 'package:invoiceninja_flutter/ui/settings/online_payments.dart';
|
||||
import 'package:invoiceninja_flutter/utils/completers.dart';
|
||||
import 'package:invoiceninja_flutter/utils/localization.dart';
|
||||
import 'package:redux/redux.dart';
|
||||
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
|
||||
|
||||
class OnlinePaymentsScreen extends StatelessWidget {
|
||||
const OnlinePaymentsScreen({Key key}) : super(key: key);
|
||||
static const String route = '/$kSettings/$kSettingsOnlinePayments';
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return StoreConnector<AppState, OnlinePaymentsVM>(
|
||||
converter: OnlinePaymentsVM.fromStore,
|
||||
builder: (context, viewModel) {
|
||||
return OnlinePayments(
|
||||
viewModel: viewModel,
|
||||
key: ValueKey(viewModel.state.settingsUIState.updatedAt),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class OnlinePaymentsVM {
|
||||
OnlinePaymentsVM({
|
||||
@required this.state,
|
||||
@required this.company,
|
||||
@required this.onCompanyChanged,
|
||||
@required this.onSavePressed,
|
||||
@required this.onSettingsChanged,
|
||||
@required this.settings,
|
||||
@required this.onConfigureGatewaysPressed,
|
||||
});
|
||||
|
||||
static OnlinePaymentsVM fromStore(Store<AppState> store) {
|
||||
final state = store.state;
|
||||
|
||||
return OnlinePaymentsVM(
|
||||
state: state,
|
||||
company: state.uiState.settingsUIState.company,
|
||||
settings: state.uiState.settingsUIState.settings,
|
||||
onCompanyChanged: (company) =>
|
||||
store.dispatch(UpdateCompany(company: company)),
|
||||
onSettingsChanged: (settings) =>
|
||||
store.dispatch(UpdateSettings(settings: settings)),
|
||||
onSavePressed: (context) {
|
||||
final settingsUIState = state.uiState.settingsUIState;
|
||||
switch (settingsUIState.entityType) {
|
||||
case EntityType.company:
|
||||
final completer = snackBarCompleter<Null>(
|
||||
context, AppLocalization.of(context).savedSettings);
|
||||
store.dispatch(SaveCompanyRequest(
|
||||
completer: completer, company: settingsUIState.company));
|
||||
break;
|
||||
case EntityType.group:
|
||||
final completer = snackBarCompleter<GroupEntity>(
|
||||
context, AppLocalization.of(context).savedSettings);
|
||||
store.dispatch(SaveGroupRequest(
|
||||
completer: completer, group: settingsUIState.group));
|
||||
break;
|
||||
case EntityType.client:
|
||||
final completer = snackBarCompleter<ClientEntity>(
|
||||
context, AppLocalization.of(context).savedSettings);
|
||||
store.dispatch(SaveClientRequest(
|
||||
completer: completer, client: settingsUIState.client));
|
||||
break;
|
||||
}
|
||||
},
|
||||
onConfigureGatewaysPressed: (context) {
|
||||
store.dispatch(ViewSettings(
|
||||
navigator: Navigator.of(context),
|
||||
section: kSettingsCompanyGateways));
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
final AppState state;
|
||||
final CompanyEntity company;
|
||||
final SettingsEntity settings;
|
||||
final Function(BuildContext) onSavePressed;
|
||||
final Function(CompanyEntity) onCompanyChanged;
|
||||
final Function(SettingsEntity) onSettingsChanged;
|
||||
final Function(BuildContext) onConfigureGatewaysPressed;
|
||||
}
|
||||
|
|
@ -284,7 +284,7 @@ class SettingsSearch extends StatelessWidget {
|
|||
'first_month_of_the_year',
|
||||
'custom_labels',
|
||||
],
|
||||
kSettingsOnlinePayments: [
|
||||
kSettingsCompanyGateways: [
|
||||
'accepted_card_logos',
|
||||
'limits_and_fees',
|
||||
],
|
||||
|
|
|
|||
|
|
@ -570,7 +570,8 @@ mixin LocalizationsProvider on LocaleCodeAware {
|
|||
'invoice_tax_rates': 'Invoice Tax Rates',
|
||||
'item_tax_rates': 'Item Tax Rates',
|
||||
'no_client_selected': 'No client selected',
|
||||
'configure_rates': 'Configure rates',
|
||||
'configure_rates': 'Configure Rates',
|
||||
'configure_gateways': 'Configure Gateways',
|
||||
'tax_settings': 'Tax Settings',
|
||||
'tax_settings_rates': 'Tax Rates',
|
||||
'accent_color': 'Accent Color',
|
||||
|
|
@ -3128,6 +3129,9 @@ mixin LocalizationsProvider on LocaleCodeAware {
|
|||
String get configureRates =>
|
||||
_localizedValues[localeCode]['configure_rates'] ?? '';
|
||||
|
||||
String get configureGateways =>
|
||||
_localizedValues[localeCode]['configure_gateways'] ?? '';
|
||||
|
||||
String get taxSettingsRates =>
|
||||
_localizedValues[localeCode]['tax_settings_rates'] ?? '';
|
||||
|
||||
|
|
|
|||
|
|
@ -150,6 +150,7 @@ IconData getSettingIcon(String section) {
|
|||
case kSettingsLocalization:
|
||||
return Icons.language;
|
||||
case kSettingsOnlinePayments:
|
||||
case kSettingsCompanyGateways:
|
||||
return MdiIcons.creditCard;
|
||||
case kSettingsTaxSettings:
|
||||
case kSettingsTaxRates:
|
||||
|
|
|
|||
Loading…
Reference in New Issue