From c5d9546767a2046263963ab6504aa40ba0c251d8 Mon Sep 17 00:00:00 2001 From: Nicolae Stihhi Date: Fri, 4 Dec 2020 11:30:01 +0200 Subject: [PATCH] 321 Added export notes button (#322) --- .../answers/answers/answers.component.html | 74 +++++++++++-------- src/app/answers/answers/answers.component.ts | 51 +++++++++---- .../components/answer/answer.component.html | 2 +- src/app/services/answers.service.ts | 19 ++++- src/assets/i18n/en.json | 1 + src/assets/i18n/ro.json | 1 + 6 files changed, 97 insertions(+), 51 deletions(-) diff --git a/src/app/answers/answers/answers.component.html b/src/app/answers/answers/answers.component.html index 832bb244..6618fdc4 100644 --- a/src/app/answers/answers/answers.component.html +++ b/src/app/answers/answers/answers.component.html @@ -5,17 +5,31 @@

{{ 'ANSWERS_HEADER_TITLE' | translate } {{ (answerState$ | async).totalItems }} total - -
- - - - - - {{ 'EXPORT' | translate }} - + +
+
+ + + + + + {{ 'EXPORT' | translate }} + +
+ +
+ + + + + + {{ 'EXPORT_NOTES' | translate }} + +
@@ -32,13 +46,13 @@

{{ 'ANSWERS_HEADER_TITLE' | translate }
- {{ 'ANSWERS_HEADER_TITLE' | translate }
- - {{ 'FILTER_BY' | translate }} {{ 'OBSERVER_PHONE' | translate | lowercase }} +
@@ -87,8 +101,8 @@

{{ 'ANSWERS_HEADER_TITLE' | translate } - +
- {{ 'FILTER' | translate }}   - {{ 'RESET' | translate }} @@ -154,4 +168,4 @@

{{ 'NO_RESULTS' | translate }}

{{ 'TRY_AGAIN_MSG' | translate }}

-
\ No newline at end of file + diff --git a/src/app/answers/answers/answers.component.ts b/src/app/answers/answers/answers.component.ts index d535f20b..774d29c9 100644 --- a/src/app/answers/answers/answers.component.ts +++ b/src/app/answers/answers/answers.component.ts @@ -1,5 +1,5 @@ -import { map, take, shareReplay, filter } from 'rxjs/operators'; +import {map, shareReplay, finalize} from 'rxjs/operators'; import { LoadAnswerDetailsAction, LoadAnswerPreviewAction, updateFilters, updatePageInfo } from '../../store/answer/answer.actions'; import { AnswerState } from '../../store/answer/answer.reducer'; import { FormState } from '../../store/form/form.reducer'; @@ -22,7 +22,6 @@ import { getCounties } from 'src/app/store/county/county.selectors'; import { AnswerExtra } from 'src/app/models/answer.extra.model'; import { FormLoadAction } from 'src/app/store/form/form.actions'; import { FormBuilder } from '@angular/forms'; -import { toFinite } from 'lodash'; const TABLE_COLUMNS = new InjectionToken('TABLE_COLUMNS', { providedIn: 'root', @@ -30,9 +29,9 @@ const TABLE_COLUMNS = new InjectionToken('TABLE_COLUMNS', { const columns: TableColumn[] = [ { name: 'ANSWERS_POLLING_STATION', propertyName: 'pollingStationName', }, { name: 'ANSWERS_NAME', propertyName: 'observerName', }, - { name: 'ANSWERS_PHONE', propertyName: 'observerPhoneNumber', }, + { name: 'ANSWERS_PHONE', propertyName: 'observerPhoneNumber', }, { name: 'ANSWERS_DATE_AND_TIME', propertyName: 'observerArrivalTime', canBeSorted: true }, - { name: 'ANSWERS_LOCATION_TYPE', propertyName: 'locationType', }, + { name: 'ANSWERS_LOCATION_TYPE', propertyName: 'locationType', }, ]; return columns; @@ -123,6 +122,31 @@ export class AnswersComponent implements OnInit { return; } + const filter = this.mapFilterKeys(rawFilters); + + this.isLoading = true; + return this.answersService.downloadAnswers(filter).subscribe(res => { + this.isLoading = false; + FileSaver.saveAs(res, 'data.csv'); + }, error => { + this.isLoading = false; + }); + } + + downloadNotes(rawFilters) { + if (!confirm(this.translate.instant('ANSWERS_DOWNLOAD_CONFIRMATION'))) { + return; + } + + const filter = this.mapFilterKeys(rawFilters); + + this.isLoading = true; + return this.answersService.downloadNotes(filter) + .pipe(finalize(() => this.isLoading = false)) + .subscribe(res => FileSaver.saveAs(res, 'notes-data.csv')); + } + + private mapFilterKeys(rawFilters) { const filterWordsDict = { county: 'county', pollingStationNumber: 'pollingStationNumber', @@ -135,21 +159,16 @@ export class AnswersComponent implements OnInit { const filter: AnswersPackFilter = {}; for (const rawKey in rawFilters) { - const rawValue = rawFilters[rawKey]; - const key = filterWordsDict[rawKey]; + if (rawFilters.hasOwnProperty(rawKey)) { + const rawValue = rawFilters[rawKey]; + const key = filterWordsDict[rawKey]; - if (this.isValidValue(rawValue)) { - filter[key] = rawValue; + if (this.isValidValue(rawValue)) { + filter[key] = rawValue; + } } } - - this.isLoading = true; - return this.answersService.downloadAnswers(filter).subscribe(res => { - this.isLoading = false; - FileSaver.saveAs(res, 'data.csv'); - }, error => { - this.isLoading = false; - }); + return filter; } private translateColumnNames(rawTableColumns: TableColumn[]) { diff --git a/src/app/components/answer/answer.component.html b/src/app/components/answer/answer.component.html index 92cab03e..08b118b9 100644 --- a/src/app/components/answer/answer.component.html +++ b/src/app/components/answer/answer.component.html @@ -12,7 +12,7 @@
- +
diff --git a/src/app/services/answers.service.ts b/src/app/services/answers.service.ts index e2f48b28..3784d057 100644 --- a/src/app/services/answers.service.ts +++ b/src/app/services/answers.service.ts @@ -3,6 +3,8 @@ import { Location } from '@angular/common'; import { Injectable } from '@angular/core'; import { ApiService, QueryParamBuilder } from '../core/apiService/api.service'; import { AnswerExtraConstructorData } from '../models/answer.extra.model'; +import {HttpParams} from '@angular/common/http'; +import {first} from 'rxjs/operators'; @Injectable({ providedIn: 'root' @@ -17,16 +19,25 @@ export class AnswersService { let paramBuilder = QueryParamBuilder .Instance('/api/v1/export/all'); - for (const key in filter) { - const value = filter[key]; - paramBuilder = paramBuilder.withParam(key, value); + for (const key in filter) { + if (filter.hasOwnProperty(key)) { + const value = filter[key]; + paramBuilder = paramBuilder.withParam(key, value); + } } const urlWithParams = paramBuilder.build(); const url: string = Location.joinWithSlash(this.baseUrl, urlWithParams); - return this.http.get(url, {responseType: 'blob' as 'json'}); + return this.http.get(url, {responseType: 'blob' as 'json'}).pipe(first()); } + downloadNotes(filter: AnswersPackFilter) { + const filterStringEntries = Object.entries(filter).map(([k, v]) => [k, v.toString()]); + const params = new HttpParams({fromObject: Object.fromEntries(filterStringEntries)}); + const url = Location.joinWithSlash(this.baseUrl, '/api/v1/export/all/notes'); + return this.http.get(url, {params, responseType: 'blob' as 'json'}).pipe(first()); + } + fetchExtraDetailsForObserver (observerId: number, sectionId: number) { return this.http.get(this.extraDetailsURL, { body: { diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index 872e1ec3..f94893d5 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -168,6 +168,7 @@ "VALIDATION_REQUIRED": "%s is required", "EXPORT": "Export answers", + "EXPORT_NOTES": "Export notes", "NO_RESULTS": "No results", "TRY_AGAIN_MSG": "Please make sure you've typed everything correctly and try again", "VIEW_NOTE": "View Note", diff --git a/src/assets/i18n/ro.json b/src/assets/i18n/ro.json index 121aba97..b8d58790 100644 --- a/src/assets/i18n/ro.json +++ b/src/assets/i18n/ro.json @@ -169,6 +169,7 @@ "VALIDATION_REQUIRED": "%s este necesar", "EXPORT": "Exportă răspunsurile", + "EXPORT_NOTES": "Exportă notele", "NO_RESULTS": "Niciun rezultat", "TRY_AGAIN_MSG": "Asigură-te că ai scris totul corect și încearcă din nou", "VIEW_NOTE": "Vezi nota",