diff --git a/lib/data/repositories/document_repository.dart b/lib/data/repositories/document_repository.dart index d9a41e21b..63c2cb214 100644 --- a/lib/data/repositories/document_repository.dart +++ b/lib/data/repositories/document_repository.dart @@ -42,6 +42,32 @@ class DocumentRepository { return documentResponse.data; } + Future> bulkAction( + Credentials credentials, List ids, EntityAction action) async { + dynamic response; + + switch (action) { + case EntityAction.restore: + case EntityAction.archive: + case EntityAction.delete: + var url = credentials.url + '/documents/bulk?include=activities'; + if (action != null) { + url += '&action=' + action.toString(); + } + response = await webClient.post(url, credentials.token, + data: json.encode([ids])); + break; + default: + // Might have other actions in the future + break; + } + + final DocumentListResponse documentResponse = + serializers.deserializeWith(DocumentListResponse.serializer, response); + + return documentResponse.data.toList(); + } + Future saveData( Credentials credentials, DocumentEntity document, [EntityAction action]) async { diff --git a/lib/redux/document/document_actions.dart b/lib/redux/document/document_actions.dart index 05e963fdf..99d2b8be9 100644 --- a/lib/redux/document/document_actions.dart +++ b/lib/redux/document/document_actions.dart @@ -136,60 +136,60 @@ class SaveDocumentFailure implements StopSaving { } class ArchiveDocumentRequest implements StartSaving { - ArchiveDocumentRequest(this.completer, this.documentId); + ArchiveDocumentRequest(this.completer, this.documentIds); final Completer completer; - final String documentId; + final List documentIds; } class ArchiveDocumentSuccess implements StopSaving, PersistData { - ArchiveDocumentSuccess(this.document); + ArchiveDocumentSuccess(this.documents); - final DocumentEntity document; + final List documents; } class ArchiveDocumentFailure implements StopSaving { - ArchiveDocumentFailure(this.document); + ArchiveDocumentFailure(this.documents); - final DocumentEntity document; + final List documents; } class DeleteDocumentRequest implements StartSaving { - DeleteDocumentRequest(this.completer, this.documentId); + DeleteDocumentRequest(this.completer, this.documentIds); final Completer completer; - final String documentId; + final List documentIds; } class DeleteDocumentSuccess implements StopSaving, PersistData { - DeleteDocumentSuccess(this.document); + DeleteDocumentSuccess(this.documents); - final DocumentEntity document; + final List documents; } class DeleteDocumentFailure implements StopSaving { - DeleteDocumentFailure(this.document); + DeleteDocumentFailure(this.documents); - final DocumentEntity document; + final List documents; } class RestoreDocumentRequest implements StartSaving { - RestoreDocumentRequest(this.completer, this.documentId); + RestoreDocumentRequest(this.completer, this.documentIds); final Completer completer; - final String documentId; + final List documentIds; } class RestoreDocumentSuccess implements StopSaving, PersistData { - RestoreDocumentSuccess(this.document); + RestoreDocumentSuccess(this.documents); - final DocumentEntity document; + final List documents; } class RestoreDocumentFailure implements StopSaving { - RestoreDocumentFailure(this.document); + RestoreDocumentFailure(this.documents); - final DocumentEntity document; + final List documents; } class FilterDocuments { @@ -244,6 +244,7 @@ void handleDocumentAction( final store = StoreProvider.of(context); final localization = AppLocalization.of(context); final document = documents.first; + final documentIds = documents.map((document) => document.id).toList(); switch (action) { case EntityAction.edit: @@ -252,17 +253,17 @@ void handleDocumentAction( case EntityAction.restore: store.dispatch(RestoreDocumentRequest( snackBarCompleter(context, localization.restoredDocument), - document.id)); + documentIds)); break; case EntityAction.archive: store.dispatch(ArchiveDocumentRequest( snackBarCompleter(context, localization.archivedDocument), - document.id)); + documentIds)); break; case EntityAction.delete: store.dispatch(DeleteDocumentRequest( snackBarCompleter(context, localization.deletedDocument), - document.id)); + documentIds)); break; case EntityAction.toggleMultiselect: if (!store.state.documentListState.isInMultiselect()) { diff --git a/lib/redux/document/document_middleware.dart b/lib/redux/document/document_middleware.dart index b02ff3ade..a2c8c340b 100644 --- a/lib/redux/document/document_middleware.dart +++ b/lib/redux/document/document_middleware.dart @@ -86,17 +86,21 @@ Middleware _viewDocumentList() { Middleware _archiveDocument(DocumentRepository repository) { return (Store store, dynamic dynamicAction, NextDispatcher next) { final action = dynamicAction as ArchiveDocumentRequest; - final origDocument = store.state.documentState.map[action.documentId]; + repository - .saveData(store.state.credentials, origDocument, EntityAction.archive) - .then((DocumentEntity document) { - store.dispatch(ArchiveDocumentSuccess(document)); + .bulkAction( + store.state.credentials, action.documentIds, EntityAction.archive) + .then((List documents) { + store.dispatch(ArchiveDocumentSuccess(documents)); if (action.completer != null) { action.completer.complete(null); } }).catchError((Object error) { print(error); - store.dispatch(ArchiveDocumentFailure(origDocument)); + final documents = action.documentIds + .map((id) => store.state.documentState.map[id]) + .toList(); + store.dispatch(ArchiveDocumentFailure(documents)); if (action.completer != null) { action.completer.completeError(error); } @@ -109,17 +113,21 @@ Middleware _archiveDocument(DocumentRepository repository) { Middleware _deleteDocument(DocumentRepository repository) { return (Store store, dynamic dynamicAction, NextDispatcher next) { final action = dynamicAction as DeleteDocumentRequest; - final origDocument = store.state.documentState.map[action.documentId]; + repository - .saveData(store.state.credentials, origDocument, EntityAction.delete) - .then((DocumentEntity document) { - store.dispatch(DeleteDocumentSuccess(document)); + .bulkAction( + store.state.credentials, action.documentIds, EntityAction.delete) + .then((List documents) { + store.dispatch(DeleteDocumentSuccess(documents)); if (action.completer != null) { action.completer.complete(null); } }).catchError((Object error) { print(error); - store.dispatch(DeleteDocumentFailure(origDocument)); + final documents = action.documentIds + .map((id) => store.state.documentState.map[id]) + .toList(); + store.dispatch(DeleteDocumentFailure(documents)); if (action.completer != null) { action.completer.completeError(error); } @@ -132,17 +140,21 @@ Middleware _deleteDocument(DocumentRepository repository) { Middleware _restoreDocument(DocumentRepository repository) { return (Store store, dynamic dynamicAction, NextDispatcher next) { final action = dynamicAction as RestoreDocumentRequest; - final origDocument = store.state.documentState.map[action.documentId]; + repository - .saveData(store.state.credentials, origDocument, EntityAction.restore) - .then((DocumentEntity document) { - store.dispatch(RestoreDocumentSuccess(document)); + .bulkAction( + store.state.credentials, action.documentIds, EntityAction.restore) + .then((List documents) { + store.dispatch(RestoreDocumentSuccess(documents)); if (action.completer != null) { action.completer.complete(null); } }).catchError((Object error) { print(error); - store.dispatch(RestoreDocumentFailure(origDocument)); + final documents = action.documentIds + .map((id) => store.state.documentState.map[id]) + .toList(); + store.dispatch(RestoreDocumentFailure(documents)); if (action.completer != null) { action.completer.completeError(error); } diff --git a/lib/redux/document/document_reducer.dart b/lib/redux/document/document_reducer.dart index 56a7de988..d0cddc36b 100644 --- a/lib/redux/document/document_reducer.dart +++ b/lib/redux/document/document_reducer.dart @@ -151,63 +151,106 @@ final documentsReducer = combineReducers([ DocumentState _archiveDocumentRequest( DocumentState documentState, ArchiveDocumentRequest action) { - final document = documentState.map[action.documentId] - .rebuild((b) => b..archivedAt = DateTime.now().millisecondsSinceEpoch); + final documents = + action.documentIds.map((id) => documentState.map[id]).toList(); - return documentState.rebuild((b) => b..map[action.documentId] = document); + for (int i = 0; i < documents.length; i++) { + documents[i] = documents[i] + .rebuild((b) => b..archivedAt = DateTime.now().millisecondsSinceEpoch); + } + return documentState.rebuild((b) { + for (final document in documents) { + b.map[document.id] = document; + } + }); } DocumentState _archiveDocumentSuccess( DocumentState documentState, ArchiveDocumentSuccess action) { - return documentState - .rebuild((b) => b..map[action.document.id] = action.document); + return documentState.rebuild((b) { + for (final document in action.documents) { + b.map[document.id] = document; + } + }); } DocumentState _archiveDocumentFailure( DocumentState documentState, ArchiveDocumentFailure action) { - return documentState - .rebuild((b) => b..map[action.document.id] = action.document); + return documentState.rebuild((b) { + for (final document in action.documents) { + b.map[document.id] = document; + } + }); } DocumentState _deleteDocumentRequest( DocumentState documentState, DeleteDocumentRequest action) { - final document = documentState.map[action.documentId].rebuild((b) => b - ..archivedAt = DateTime.now().millisecondsSinceEpoch - ..isDeleted = true); + final documents = + action.documentIds.map((id) => documentState.map[id]).toList(); - return documentState.rebuild((b) => b..map[action.documentId] = document); + for (int i = 0; i < documents.length; i++) { + documents[i] = documents[i].rebuild((b) => b + ..archivedAt = DateTime.now().millisecondsSinceEpoch + ..isDeleted = true); + } + return documentState.rebuild((b) { + for (final document in documents) { + b.map[document.id] = document; + } + }); } DocumentState _deleteDocumentSuccess( DocumentState documentState, DeleteDocumentSuccess action) { - return documentState.rebuild((b) => - b..map.remove(action.document.id)..list.remove(action.document.id)); + return documentState.rebuild((b) { + for (final document in action.documents) { + b.map[document.id] = document; + } + }); } DocumentState _deleteDocumentFailure( DocumentState documentState, DeleteDocumentFailure action) { - return documentState - .rebuild((b) => b..map[action.document.id] = action.document); + return documentState.rebuild((b) { + for (final document in action.documents) { + b.map[document.id] = document; + } + }); } DocumentState _restoreDocumentRequest( DocumentState documentState, RestoreDocumentRequest action) { - final document = documentState.map[action.documentId].rebuild((b) => b - ..archivedAt = null - ..isDeleted = false); - return documentState.rebuild((b) => b..map[action.documentId] = document); + final documents = + action.documentIds.map((id) => documentState.map[id]).toList(); + + for (int i = 0; i < documents.length; i++) { + documents[i] = documents[i].rebuild((b) => b + ..archivedAt = null + ..isDeleted = false); + } + return documentState.rebuild((b) { + for (final document in documents) { + b.map[document.id] = document; + } + }); } DocumentState _restoreDocumentSuccess( DocumentState documentState, RestoreDocumentSuccess action) { - return documentState - .rebuild((b) => b..map[action.document.id] = action.document); + return documentState.rebuild((b) { + for (final document in action.documents) { + b.map[document.id] = document; + } + }); } DocumentState _restoreDocumentFailure( DocumentState documentState, RestoreDocumentFailure action) { - return documentState - .rebuild((b) => b..map[action.document.id] = action.document); + return documentState.rebuild((b) { + for (final document in action.documents) { + b.map[document.id] = document; + } + }); } DocumentState _addDocument( diff --git a/lib/ui/expense/view/expense_view_vm.dart b/lib/ui/expense/view/expense_view_vm.dart index 47b4f0a53..a63759a87 100644 --- a/lib/ui/expense/view/expense_view_vm.dart +++ b/lib/ui/expense/view/expense_view_vm.dart @@ -172,7 +172,7 @@ class ExpenseViewVM { store.dispatch(DeleteDocumentRequest( snackBarCompleter( context, AppLocalization.of(context).deletedDocument), - document.id)); + [document.id])); }); } diff --git a/lib/ui/invoice/view/invoice_view_vm.dart b/lib/ui/invoice/view/invoice_view_vm.dart index f6832fbb0..abe308a41 100644 --- a/lib/ui/invoice/view/invoice_view_vm.dart +++ b/lib/ui/invoice/view/invoice_view_vm.dart @@ -213,7 +213,7 @@ class InvoiceViewVM extends EntityViewVM { store.dispatch(DeleteDocumentRequest( snackBarCompleter( context, AppLocalization.of(context).deletedDocument), - document.id)); + [document.id])); }, onViewExpense: (BuildContext context, DocumentEntity document) { store.dispatch( diff --git a/lib/ui/quote/view/quote_view_vm.dart b/lib/ui/quote/view/quote_view_vm.dart index c6d25bcff..490c32bed 100644 --- a/lib/ui/quote/view/quote_view_vm.dart +++ b/lib/ui/quote/view/quote_view_vm.dart @@ -158,7 +158,7 @@ class QuoteViewVM extends EntityViewVM { store.dispatch(DeleteDocumentRequest( snackBarCompleter( context, AppLocalization.of(context).deletedDocument), - document.id)); + [document.id])); }, ); }