Pull to refresh a payment/product

This commit is contained in:
Hillel Coren 2020-08-09 17:50:13 +03:00
parent fc6b310774
commit ae5abc084c
5 changed files with 104 additions and 77 deletions

View File

@ -16,6 +16,18 @@ class PaymentRepository {
final WebClient webClient;
Future<PaymentEntity> loadItem(
Credentials credentials, String entityId) async {
final String url = '${credentials.url}/payments/$entityId';
final dynamic response = await webClient.get(url, credentials.token);
final PaymentItemResponse paymentResponse = await compute<dynamic, dynamic>(
computeDecode, <dynamic>[PaymentItemResponse.serializer, response]);
return paymentResponse.data;
}
Future<BuiltList<PaymentEntity>> loadList(Credentials credentials) async {
final url = credentials.url + '/payments?include=paymentables';

View File

@ -22,7 +22,7 @@ List<Middleware<AppState>> createStorePaymentsMiddleware([
final editPayment = _editPayment();
final viewRefundPayment = _viewRefundPayment();
final loadPayments = _loadPayments(repository);
//final loadPayment = _loadPayment(repository);
final loadPayment = _loadPayment(repository);
final savePayment = _savePayment(repository);
final refundPayment = _refundPayment(repository);
final archivePayment = _archivePayment(repository);
@ -36,7 +36,7 @@ List<Middleware<AppState>> createStorePaymentsMiddleware([
TypedMiddleware<AppState, EditPayment>(editPayment),
TypedMiddleware<AppState, ViewRefundPayment>(viewRefundPayment),
TypedMiddleware<AppState, LoadPayments>(loadPayments),
//TypedMiddleware<AppState, LoadPayment>(loadPayment),
TypedMiddleware<AppState, LoadPayment>(loadPayment),
TypedMiddleware<AppState, SavePaymentRequest>(savePayment),
TypedMiddleware<AppState, RefundPaymentRequest>(refundPayment),
TypedMiddleware<AppState, ArchivePaymentsRequest>(archivePayment),
@ -257,9 +257,9 @@ Middleware<AppState> _emailPayment(PaymentRepository repository) {
};
}
/*
Middleware<AppState> _loadPayment(PaymentRepository repository) {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
final action = dynamicAction as LoadPayment;
final AppState state = store.state;
if (state.isLoading) {
@ -287,7 +287,7 @@ Middleware<AppState> _loadPayment(PaymentRepository repository) {
next(action);
};
}
*/
Middleware<AppState> _loadPayments(PaymentRepository repository) {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {

View File

@ -68,73 +68,77 @@ class _PaymentViewState extends State<PaymentView> {
title: payment.number,
body: Builder(
builder: (BuildContext context) {
return Column(
children: <Widget>[
Expanded(
child: ListView(
children: <Widget>[
EntityHeader(
entity: payment,
statusColor: PaymentStatusColors.colors[payment.statusId],
statusLabel: localization
.lookup('payment_status_${payment.statusId}'),
label: localization.amount,
value: formatNumber(payment.amount, context,
clientId: client.id),
secondLabel: localization.applied,
secondValue: formatNumber(payment.applied, context,
clientId: client.id),
),
ListDivider(),
EntityListTile(
isFilter: widget.isFilter,
entity: client,
),
for (final paymentable in payment.invoicePaymentables)
return RefreshIndicator(
onRefresh: () => viewModel.onRefreshed(context),
child: Column(
children: <Widget>[
Expanded(
child: ListView(
children: <Widget>[
EntityHeader(
entity: payment,
statusColor:
PaymentStatusColors.colors[payment.statusId],
statusLabel: localization
.lookup('payment_status_${payment.statusId}'),
label: localization.amount,
value: formatNumber(payment.amount, context,
clientId: client.id),
secondLabel: localization.applied,
secondValue: formatNumber(payment.applied, context,
clientId: client.id),
),
ListDivider(),
EntityListTile(
isFilter: widget.isFilter,
entity: state.invoiceState.map[paymentable.invoiceId],
subtitle: formatNumber(paymentable.amount, context) +
'' +
formatDate(
convertTimestampToDateString(
paymentable.createdAt),
context),
entity: client,
),
for (final paymentable in payment.creditPaymentables)
EntityListTile(
isFilter: widget.isFilter,
entity: state.creditState.map[paymentable.creditId],
subtitle: formatNumber(paymentable.amount, context) +
'' +
formatDate(
convertTimestampToDateString(
paymentable.createdAt),
context),
),
payment.privateNotes != null &&
payment.privateNotes.isNotEmpty
? Column(
children: <Widget>[
IconMessage(payment.privateNotes),
Container(
color: Theme.of(context).cardColor,
height: 12.0,
),
],
)
: Container(),
FieldGrid(fields),
],
for (final paymentable in payment.invoicePaymentables)
EntityListTile(
isFilter: widget.isFilter,
entity: state.invoiceState.map[paymentable.invoiceId],
subtitle: formatNumber(paymentable.amount, context) +
'' +
formatDate(
convertTimestampToDateString(
paymentable.createdAt),
context),
),
for (final paymentable in payment.creditPaymentables)
EntityListTile(
isFilter: widget.isFilter,
entity: state.creditState.map[paymentable.creditId],
subtitle: formatNumber(paymentable.amount, context) +
'' +
formatDate(
convertTimestampToDateString(
paymentable.createdAt),
context),
),
payment.privateNotes != null &&
payment.privateNotes.isNotEmpty
? Column(
children: <Widget>[
IconMessage(payment.privateNotes),
Container(
color: Theme.of(context).cardColor,
height: 12.0,
),
],
)
: Container(),
FieldGrid(fields),
],
),
),
),
BottomButtons(
entity: payment,
action1: EntityAction.refund,
action1Enabled: payment.refunded < payment.amount,
action2: EntityAction.archive,
),
],
BottomButtons(
entity: payment,
action1: EntityAction.refund,
action1Enabled: payment.refunded < payment.amount,
action2: EntityAction.archive,
),
],
),
);
},
),

View File

@ -5,7 +5,10 @@ import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/data/models/payment_model.dart';
import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
import 'package:invoiceninja_flutter/redux/payment/payment_actions.dart';
import 'package:invoiceninja_flutter/ui/payment/view/payment_view.dart';
import 'package:invoiceninja_flutter/utils/completers.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
import 'package:redux/redux.dart';
class PaymentViewScreen extends StatelessWidget {
@ -38,6 +41,7 @@ class PaymentViewVM {
@required this.payment,
@required this.company,
@required this.onEntityAction,
@required this.onRefreshed,
@required this.isSaving,
@required this.isLoading,
@required this.isDirty,
@ -48,6 +52,16 @@ class PaymentViewVM {
final payment = state.paymentState.map[state.paymentUIState.selectedId] ??
PaymentEntity(id: state.paymentUIState.selectedId);
Future<Null> _handleRefresh(BuildContext context) {
final completer = snackBarCompleter<Null>(
context, AppLocalization.of(context).refreshComplete);
store.dispatch(LoadPayment(
completer: completer,
paymentId: payment.id,
));
return completer.future;
}
return PaymentViewVM(
state: state,
company: state.company,
@ -55,6 +69,7 @@ class PaymentViewVM {
isDirty: payment.isNew,
isLoading: state.isLoading,
payment: payment,
onRefreshed: (context) => _handleRefresh(context),
onEntityAction: (BuildContext context, EntityAction action) =>
handleEntitiesActions(context, [payment], action, autoPop: true),
);
@ -64,6 +79,7 @@ class PaymentViewVM {
final PaymentEntity payment;
final CompanyEntity company;
final Function(BuildContext, EntityAction) onEntityAction;
final Function(BuildContext) onRefreshed;
final bool isSaving;
final bool isLoading;
final bool isDirty;

View File

@ -59,16 +59,15 @@ class ProductViewVM {
final product = state.productState.map[state.productUIState.selectedId] ??
ProductEntity(id: state.productUIState.selectedId);
/*
Future<Null> _handleRefresh(BuildContext context) {
final completer = snackBarCompleter<Null>(
context, AppLocalization.of(context).refreshComplete);
store.dispatch(LoadProduct(
completer: completer,
productId: product.id,));
completer: completer,
productId: product.id,
));
return completer.future;
}
*/
return ProductViewVM(
state: state,
@ -77,11 +76,7 @@ class ProductViewVM {
isDirty: product.isNew,
product: product,
company: state.company,
onRefreshed: null,
/*
onRefreshed: (context) =>
_handleRefresh(context),
*/
onRefreshed: (context) => _handleRefresh(context),
onEntityAction: (BuildContext context, EntityAction action) =>
handleEntitiesActions(context, [product], action, autoPop: true),
onUploadDocument: (BuildContext context, String filePath) {
@ -105,7 +100,7 @@ class ProductViewVM {
final completer = snackBarCompleter<Null>(
context, AppLocalization.of(context).deletedDocument);
completer.future.then<Null>(
(value) => store.dispatch(LoadProduct(productId: product.id)));
(value) => store.dispatch(LoadProduct(productId: product.id)));
store.dispatch(DeleteDocumentRequest(completer, [document.id]));
},
);