diff --git a/lib/constants.dart b/lib/constants.dart index ab32fae6c..57bcb82fa 100644 --- a/lib/constants.dart +++ b/lib/constants.dart @@ -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'; diff --git a/lib/main_app.dart b/lib/main_app.dart index 314378a64..bc6ea7b32 100644 --- a/lib/main_app.dart +++ b/lib/main_app.dart @@ -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 { 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 { CompanyDetailsScreen(), UserDetailsScreen.route: (context) => UserDetailsScreen(), LocalizationScreen.route: (context) => LocalizationScreen(), + OnlinePaymentsScreen.route: (context) => + OnlinePaymentsScreen(), CompanyGatewayScreen.route: (context) => CompanyGatewayScreenBuilder(), CompanyGatewayViewScreen.route: (context) => diff --git a/lib/ui/app/main_screen.dart b/lib/ui/app/main_screen.dart index 9e8ee4f10..09e9160c0 100644 --- a/lib/ui/app/main_screen.dart +++ b/lib/ui/app/main_screen.dart @@ -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: diff --git a/lib/ui/company_gateway/company_gateway_list.dart b/lib/ui/company_gateway/company_gateway_list.dart index 481b939b0..c2f46c4d7 100644 --- a/lib/ui/company_gateway/company_gateway_list.dart +++ b/lib/ui/company_gateway/company_gateway_list.dart @@ -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,190 +21,38 @@ class CompanyGatewayList extends StatelessWidget { final listUIState = state.uiState.companyGatewayUIState.listUIState; final isInMultiselect = listUIState.isInMultiselect(); - return ListView( - shrinkWrap: true, - children: [ - _OnlinePaymentForm( - viewModel: viewModel, - key: ValueKey('__settings_${state.settingsUIState.updatedAt}__'), - ), - !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 - // These two lines are workarounds for ReorderableListView problems - if (newIndex > viewModel.companyGatewayList.length) { - newIndex = viewModel.companyGatewayList.length; - } - if (oldIndex < newIndex) { - newIndex--; - } + return !viewModel.state.isLoaded && viewModel.companyGatewayList.isEmpty + ? LoadingIndicator() + : RefreshIndicator( + onRefresh: () => viewModel.onRefreshed(context), + child: ReorderableListView( + onReorder: (oldIndex, newIndex) { + // https://stackoverflow.com/a/54164333/497368 + // These two lines are workarounds for ReorderableListView problems + if (newIndex > viewModel.companyGatewayList.length) { + newIndex = viewModel.companyGatewayList.length; + } + if (oldIndex < newIndex) { + newIndex--; + } - viewModel.onSortChanged(oldIndex, newIndex); - }, - children: - viewModel.companyGatewayList.map((companyGatewayId) { - final companyGateway = - viewModel.companyGatewayMap[companyGatewayId]; - return CompanyGatewayListItem( - key: ValueKey('__company_gateway_$companyGatewayId'), - user: state.userCompany.user, - filter: viewModel.filter, - companyGateway: companyGateway, - 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 _formKey = - GlobalKey(debugLabel: '_companyGatewayList'); - final FocusScopeNode _focusNode = FocusScopeNode(); - - //bool _autoValidate = false; - - final _minimumAmountController = TextEditingController(); - - List _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( - 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( - 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, - ), - ), - ]), - ); + viewModel.onSortChanged(oldIndex, newIndex); + }, + children: viewModel.companyGatewayList.map((companyGatewayId) { + final companyGateway = + viewModel.companyGatewayMap[companyGatewayId]; + return CompanyGatewayListItem( + key: ValueKey('__company_gateway_$companyGatewayId'), + user: state.userCompany.user, + filter: viewModel.filter, + companyGateway: companyGateway, + onRemovePressed: viewModel.state.settingsUIState.isFiltered + ? () => viewModel.onRemovePressed(companyGatewayId) + : null, + isChecked: isInMultiselect && + listUIState.isSelected(companyGateway.id)); + }).toList(), + ), + ); } } diff --git a/lib/ui/company_gateway/company_gateway_list_vm.dart b/lib/ui/company_gateway/company_gateway_list_vm.dart index 0c89fbc90..0e4d7814d 100644 --- a/lib/ui/company_gateway/company_gateway_list_vm.dart +++ b/lib/ui/company_gateway/company_gateway_list_vm.dart @@ -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 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; } diff --git a/lib/ui/company_gateway/company_gateway_screen.dart b/lib/ui/company_gateway/company_gateway_screen.dart index 881353305..3ad221c85 100644 --- a/lib/ui/company_gateway/company_gateway_screen.dart +++ b/lib/ui/company_gateway/company_gateway_screen.dart @@ -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; diff --git a/lib/ui/company_gateway/edit/company_gateway_edit_vm.dart b/lib/ui/company_gateway/edit/company_gateway_edit_vm.dart index 60e43c37d..b1774d444 100644 --- a/lib/ui/company_gateway/edit/company_gateway_edit_vm.dart +++ b/lib/ui/company_gateway/edit/company_gateway_edit_vm.dart @@ -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) { diff --git a/lib/ui/company_gateway/view/company_gateway_view_vm.dart b/lib/ui/company_gateway/view/company_gateway_view_vm.dart index d4dc1d712..25b0a1fc8 100644 --- a/lib/ui/company_gateway/view/company_gateway_view_vm.dart +++ b/lib/ui/company_gateway/view/company_gateway_view_vm.dart @@ -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) { diff --git a/lib/ui/settings/online_payments.dart b/lib/ui/settings/online_payments.dart new file mode 100644 index 000000000..dfe00344a --- /dev/null +++ b/lib/ui/settings/online_payments.dart @@ -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 { + static final GlobalKey _formKey = + GlobalKey(debugLabel: '_onlinePayments'); + FocusScopeNode _focusNode; + final _minimumAmountController = TextEditingController(); + List _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: [ + FormCard(children: [ + AppDropdownButton( + 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( + 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), + ), + ), + ], + ), + ); + } +} diff --git a/lib/ui/settings/online_payments_vm.dart b/lib/ui/settings/online_payments_vm.dart new file mode 100644 index 000000000..351203c5d --- /dev/null +++ b/lib/ui/settings/online_payments_vm.dart @@ -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( + 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 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( + context, AppLocalization.of(context).savedSettings); + store.dispatch(SaveCompanyRequest( + completer: completer, company: settingsUIState.company)); + break; + case EntityType.group: + final completer = snackBarCompleter( + context, AppLocalization.of(context).savedSettings); + store.dispatch(SaveGroupRequest( + completer: completer, group: settingsUIState.group)); + break; + case EntityType.client: + final completer = snackBarCompleter( + 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; +} diff --git a/lib/ui/settings/settings_list.dart b/lib/ui/settings/settings_list.dart index e89b0a384..b0bab2b63 100644 --- a/lib/ui/settings/settings_list.dart +++ b/lib/ui/settings/settings_list.dart @@ -284,7 +284,7 @@ class SettingsSearch extends StatelessWidget { 'first_month_of_the_year', 'custom_labels', ], - kSettingsOnlinePayments: [ + kSettingsCompanyGateways: [ 'accepted_card_logos', 'limits_and_fees', ], diff --git a/lib/utils/i18n.dart b/lib/utils/i18n.dart index 4247b0972..58b69e16d 100644 --- a/lib/utils/i18n.dart +++ b/lib/utils/i18n.dart @@ -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'] ?? ''; diff --git a/lib/utils/icons.dart b/lib/utils/icons.dart index ba312c208..834c12e59 100644 --- a/lib/utils/icons.dart +++ b/lib/utils/icons.dart @@ -150,6 +150,7 @@ IconData getSettingIcon(String section) { case kSettingsLocalization: return Icons.language; case kSettingsOnlinePayments: + case kSettingsCompanyGateways: return MdiIcons.creditCard; case kSettingsTaxSettings: case kSettingsTaxRates: