diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index 6cdeb920..f0c8b6e7 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -47,7 +47,7 @@ import { HeaderComponent } from 'app/shared/header/header.component';
import { NavigationComponent } from 'app/shared/navigation/navigation.component';
import { UsersService } from 'app/services/users.service';
import { FmusService } from 'app/services/fmus.service';
-// import { TabsComponent } from 'app/shared/tabs/tabs.component';
+import { TabsComponent } from 'app/shared/tabs/tabs.component';
import { ObservationDetailComponent } from 'app/pages/observations/observation-detail.component';
import { FieldListComponent } from 'app/pages/fields/field-list.component';
import { FieldDetailComponent } from 'app/pages/fields/field-detail.component';
@@ -121,7 +121,7 @@ export function createTranslateLoader(http: HttpClient) {
ProfileComponent,
FieldListComponent,
FieldDetailComponent,
- // TabsComponent,
+ TabsComponent,
NavigationComponent,
NavigationItemDirective,
HeaderComponent,
diff --git a/src/app/models/draft_observation.interface.ts b/src/app/models/draft_observation.interface.ts
index bb641a46..1c9707a0 100644
--- a/src/app/models/draft_observation.interface.ts
+++ b/src/app/models/draft_observation.interface.ts
@@ -23,6 +23,7 @@ export interface DraftObservation {
// New evidence
evidenceTitle?: string;
evidenceAttachment?: string; // Base64
+ evidenceDocumentType?: string;
isPhysicalPlace?: boolean;
litigationStatus?: string;
diff --git a/src/app/models/observation_document.ts b/src/app/models/observation_document.ts
index bc61e779..4b99654d 100644
--- a/src/app/models/observation_document.ts
+++ b/src/app/models/observation_document.ts
@@ -1,5 +1,5 @@
import { Observation } from 'app/models/observation.model';
-import { User } from 'app/models/user.model';
+import { ObservationReport } from 'app/models/observation_report';
import { JsonApiModel, JsonApiModelConfig, Attribute, BelongsTo } from 'angular2-jsonapi';
@JsonApiModelConfig({
@@ -8,7 +8,9 @@ import { JsonApiModel, JsonApiModelConfig, Attribute, BelongsTo } from 'angular2
export class ObservationDocument extends JsonApiModel {
@Attribute() name: string;
+ @Attribute() 'document-type': string;
@Attribute() attachment: string|{ url: string };
@BelongsTo() observation: Observation;
+ @BelongsTo() 'observation-report'?: ObservationReport;
}
diff --git a/src/app/models/observation_report.ts b/src/app/models/observation_report.ts
index c8d80887..f1f0e966 100644
--- a/src/app/models/observation_report.ts
+++ b/src/app/models/observation_report.ts
@@ -14,5 +14,6 @@ export class ObservationReport extends JsonApiModel {
@Attribute({ converter: new DateConverter() }) 'publication-date': Date;
@HasMany() observers: Observer[];
+ @HasMany() observations: Observation[];
}
diff --git a/src/app/pages/observations/observation-detail.component.html b/src/app/pages/observations/observation-detail.component.html
index 3f5146e0..596aa189 100644
--- a/src/app/pages/observations/observation-detail.component.html
+++ b/src/app/pages/observations/observation-detail.component.html
@@ -85,6 +85,124 @@
{{'Edit observation' | tra
{{'observation.statusNote.Published' | translate}}
+
+
+
+
-
+
@@ -832,92 +865,7 @@
{{'Upload report' | translate}}
-
+
diff --git a/src/app/pages/observations/observation-detail.component.scss b/src/app/pages/observations/observation-detail.component.scss
index fce2c80a..90c0a73b 100644
--- a/src/app/pages/observations/observation-detail.component.scss
+++ b/src/app/pages/observations/observation-detail.component.scss
@@ -54,6 +54,8 @@
padding: 0;
border-top: 1px solid $lighter-grey;
border-bottom: 1px solid $lighter-grey;
+ max-height: 400px;
+ overflow: auto;
> li {
display: flex;
diff --git a/src/app/pages/observations/observation-detail.component.ts b/src/app/pages/observations/observation-detail.component.ts
index 9b7d4ce4..8e701c03 100644
--- a/src/app/pages/observations/observation-detail.component.ts
+++ b/src/app/pages/observations/observation-detail.component.ts
@@ -1,6 +1,8 @@
import { TranslateService } from '@ngx-translate/core';
-import * as cloneDeep from 'lodash/cloneDeep';
-import * as orderBy from 'lodash/orderBy';
+import cloneDeep from 'lodash/cloneDeep';
+import orderBy from 'lodash/orderBy';
+import uniqBy from 'lodash/uniqBy';
+import flatten from 'lodash/flatten';
import * as EXIF from 'exif-js';
import proj4 from 'proj4';
import { Law } from 'app/models/law.model';
@@ -75,12 +77,26 @@ export class ObservationDetailComponent implements OnDestroy {
documents: ObservationDocument[] = []; // Sorted by name initially
documentsToDelete: ObservationDocument[] = []; // Existing document to delete
documentsToUpload: ObservationDocument[] = []; // New document to upload
+ reportDocuments: ObservationDocument[] = []; // Documents of the selected report
evidence: ObservationDocument = this.datastoreService.createRecord(ObservationDocument, {});
- evidenceTypes = [ // Possible types of an evidence
- 'Government Documents', 'Company Documents', 'Photos',
- 'Testimony from local communities', 'Other', 'Evidence presented in the report'
+ evidenceTypes = [
+ 'No evidence', 'Uploaded documents', 'Evidence presented in the report'
];
evidenceTypeOptions: any = {}; // Object of options for evidence type selection
+ documentTypes = [ // Possible types of an observation document/evidence
+ 'Government Documents', 'Company Documents', 'Photos',
+ 'Testimony from local communities', 'Other'
+ ];
+ documentTypeOptions: any = {}; // Object of options for document type selection
+
+ evidenceTabs = [{
+ id: 'existing',
+ name: 'Select from report evidences'
+ }, {
+ id: 'new',
+ name: 'Upload a new evidence'
+ }]
+ currentEvidenceTab = this.evidenceTabs[0];
coordinatesFormats = [
'Decimal',
@@ -648,6 +664,10 @@ export class ObservationDetailComponent implements OnDestroy {
);
}
+ get isEvidenceOnReport() {
+ return this._evidenceType === 'Evidence presented in the report';
+ }
+
get mapLayers(): any[] {
const layers = [];
@@ -675,6 +695,24 @@ export class ObservationDetailComponent implements OnDestroy {
get reportChoice() { return this.observation ? (this.observation['observation-report'] || null) : this._reportChoice; }
set reportChoice(reportChoice) {
+ if (reportChoice && reportChoice.id) {
+ this.observationDocumentsService.getAll({ filter: { 'observation-report-id': reportChoice.id } }).then((documents) => {
+ this.reportDocuments = orderBy(
+ uniqBy(documents, 'id'),
+ [(d) => d.name.toLowerCase()]
+ );
+ });
+
+ // this.observationReportsService.getById(reportChoice.id, { include: 'observations,observations.observation-documents' }).then((report) => {
+ // if (report.observations && report.observations.length > 0) {
+ // this.reportDocuments = orderBy(
+ // uniqBy(flatten(report.observations.map(o => o['observation-documents'])), 'id'),
+ // [(d) => d.name.toLowerCase()]
+ // );
+ // }
+ // });
+ }
+
if (this.observation) {
this.observation['observation-report'] = reportChoice;
} else {
@@ -759,12 +797,14 @@ export class ObservationDetailComponent implements OnDestroy {
private translateService: TranslateService
) {
this.updateTranslatedOptions(this.evidenceTypes, 'evidenceType');
+ this.updateTranslatedOptions(this.documentTypes, 'documentType');
this.updateTranslatedOptions(this.coordinatesFormats, 'coordinatesFormat');
this.updateMultiSelectTexts();
this.translateService.onLangChange.subscribe(() => {
this.updateTranslatedOptions(this.evidenceTypes, 'evidenceType');
+ this.updateTranslatedOptions(this.documentTypes, 'documentType');
this.updateTranslatedOptions(this.coordinatesFormats, 'coordinatesFormat');
});
@@ -873,6 +913,7 @@ export class ObservationDetailComponent implements OnDestroy {
// If we were going to add an evidence
this.evidence.name = this.draft.evidenceTitle;
this.evidence.attachment = this.draft.evidenceAttachment;
+ this.evidence['document-type'] = this.draft.evidenceDocumentType;
// if we were going to upload a new report
this.report.title = this.draft.reportTitle;
this.reportAttachment = this.draft.reportAttachment;
@@ -929,6 +970,7 @@ export class ObservationDetailComponent implements OnDestroy {
}
public onChangeEvidenceType(previousType: string, type: string, typeElement: HTMLSelectElement): void {
+ console.log('on change evidence type', previousType, type, typeElement);
if (!this.isEvidenceTypeOnReport(type) || !this.documents.length) {
this.evidenceType = type;
}
@@ -939,6 +981,7 @@ export class ObservationDetailComponent implements OnDestroy {
if (confirm(phrase)) {
this.evidenceType = type;
this.evidence.name = null;
+ this.evidence['document-type'] = null;
this.evidence.attachment = null;
this.georeferencedPhoto.isUsed = false;
this.evidenceInput.nativeElement.value = '';
@@ -946,11 +989,14 @@ export class ObservationDetailComponent implements OnDestroy {
typeElement.selectedIndex = this.evidenceTypes.indexOf(previousType) + 1;
}
});
- } else {
- this.evidenceOnReport = null;
}
}
+ // public onChangeDocumentType(type: string): void {
+ // console.log('onChangeEvidenceCategory', previousType, type, typeElement);
+ // this.evidenceCategory = type;
+ // }
+
private saveAsDraftObservation(): void {
const draftModel: DraftObservation = {
observationType: this.type,
@@ -966,6 +1012,7 @@ export class ObservationDetailComponent implements OnDestroy {
evidenceOnReport: this.evidenceOnReport,
evidenceTitle: this.evidence.name,
evidenceAttachment: this.evidence.attachment && String(this.evidence.attachment),
+ evidenceDocumentType: this.evidence['document-type'],
documents: this.documents.map(document => ({
name: document.name,
attachement: document.attachment
@@ -1277,9 +1324,12 @@ export class ObservationDetailComponent implements OnDestroy {
* Event handler executed when the user clicks the "Add evidence" button
*/
onClickAddEvidence() {
+ console.log('evidence name', this.evidence.name);
+ console.log('evidence type', this.evidence['document-type']);
+
const evidence = this.datastoreService.createRecord(ObservationDocument, {
name: this.evidence.name,
- type: this.evidence.type,
+ ['document-type']: this.evidence['document-type'],
attachment: this.evidence.attachment
});
@@ -1295,6 +1345,12 @@ export class ObservationDetailComponent implements OnDestroy {
this.georeferencedPhoto.isUsed = false;
}
+ onClickAddReportDocument(document: ObservationDocument) {
+ let documentIndex = this.reportDocuments.findIndex(d => d === document);
+ this.reportDocuments.splice(documentIndex, 1);
+ document.fromReportLibrary = true;
+ this.documents.push(document);
+ }
/**
* Event handler executed when the user clicks the delete button
* of an evidence
@@ -1308,9 +1364,13 @@ export class ObservationDetailComponent implements OnDestroy {
this.documents.splice(documentIndex, 1);
if (document.id) {
- // If the document is an existing one, we add it
- // to the list of documents to delete
- this.documentsToDelete.push(cloneDeep(document));
+ this.reportDocuments.push(document);
+ this.reportDocuments = orderBy(this.reportDocuments, [(d) => d.name.toLowerCase()]);
+ // else {
+ // // If the document is an existing one, we add it
+ // // to the list of documents to delete
+ // this.documentsToDelete.push(cloneDeep(document));
+ // }
} else {
// We get the index of the document within this.documentsToUpload
documentIndex = this.documentsToUpload.findIndex((d) => {
@@ -1334,6 +1394,10 @@ export class ObservationDetailComponent implements OnDestroy {
this.needsRevisionState = 'explain';
}
+ onChangeEvidenceTab(tab) {
+ this.currentEvidenceTab = tab;
+ }
+
/**
* Return whether the form is disabled
* @returns {boolean}
@@ -1548,18 +1612,20 @@ export class ObservationDetailComponent implements OnDestroy {
*/
updateDocuments(observation: Observation): Promise<{}> {
// We create an array of the documents to delete
- const deletePromises = this.documentsToDelete.map((d) => {
- return this.datastoreService.deleteRecord(ObservationDocument, d.id)
- .toPromise();
- });
+ // const deletePromises = this.documentsToDelete.map((d) => {
+ // return this.datastoreService.deleteRecord(ObservationDocument, d.id)
+ // .toPromise();
+ // });
// We create an array of the documents to upload
const uploadPromises = !this.isEvidenceTypeOnReport(this.evidenceType) ? this.documentsToUpload.map((d) => {
d.observation = observation; // We link the document to the observation
+ d['observation-report'] = observation['observation-report']; // We link the document to the report
return d.save().toPromise();
}) : [];
- return Promise.all(deletePromises.concat(
uploadPromises));
+ // return Promise.all(deletePromises.concat(uploadPromises));
+ return Promise.all(uploadPromises);
}
async onSubmitForReview() {
diff --git a/src/app/shared/tabs/tabs.component.ts b/src/app/shared/tabs/tabs.component.ts
index 4ac93a65..3cfa7449 100644
--- a/src/app/shared/tabs/tabs.component.ts
+++ b/src/app/shared/tabs/tabs.component.ts
@@ -1,76 +1,76 @@
-// import { Component, Input, HostListener, Output, EventEmitter } from '@angular/core';
+import { Component, Input, HostListener, Output, EventEmitter } from '@angular/core';
-// export interface Tab {
-// id: string;
-// name: string;
-// }
+export interface Tab {
+ id: string;
+ name: string;
+}
-// @Component({
-// selector: 'otp-tabs',
-// templateUrl: './tabs.component.html',
-// styleUrls: ['./tabs.component.scss']
-// })
-// export class TabsComponent {
+@Component({
+ selector: 'otp-tabs',
+ templateUrl: './tabs.component.html',
+ styleUrls: ['./tabs.component.scss']
+})
+export class TabsComponent {
-// @Input() tabs: Tab[] = [];
-// @Input() currentTab = 0; // Index of the current Tab
-// @Output() change: EventEmitter = new EventEmitter();
+ @Input() tabs: Tab[] = [];
+ @Input() currentTab = 0; // Index of the current Tab
+ @Output() change: EventEmitter = new EventEmitter();
-// get tab () {
-// return this.tabs[this.currentTab];
-// }
+ get tab () {
+ return this.tabs[this.currentTab];
+ }
-// set tab (tab: Tab) {
-// this.currentTab = this.tabs.findIndex(function (t) {
-// return t === tab;
-// });
+ set tab (tab: Tab) {
+ this.currentTab = this.tabs.findIndex(function (t) {
+ return t === tab;
+ });
-// this.change.emit(this.tab);
-// }
+ this.change.emit(this.tab);
+ }
-// /**
-// * Event handler executed when the user clicks a tab
-// * @param {TabItem} tab clicked tab
-// */
-// onClickTab (tab: Tab): void {
-// this.tab = tab;
-// }
+ /**
+ * Event handler executed when the user clicks a tab
+ * @param {TabItem} tab clicked tab
+ */
+ onClickTab (tab: Tab): void {
+ this.tab = tab;
+ }
-// /**
-// * Event handler executed when the user presses a key while the focus
-// * is on the component
-// * @param {KeyboardEvent} e event
-// */
-// @HostListener('keydown',['$event'])
-// onKeydown (e: KeyboardEvent) {
-// switch (e.keyCode) {
-// case 37: // left arrow
-// case 38: // top arrow
-// let previousTabIndex = (this.currentTab - 1) % this.tabs.length;
-// if (previousTabIndex < 0) {
-// previousTabIndex = this.tabs.length - 1;
-// }
-// this.tab = this.getTab(previousTabIndex);
-// break;
+ /**
+ * Event handler executed when the user presses a key while the focus
+ * is on the component
+ * @param {KeyboardEvent} e event
+ */
+ @HostListener('keydown',['$event'])
+ onKeydown (e: KeyboardEvent) {
+ switch (e.keyCode) {
+ case 37: // left arrow
+ case 38: // top arrow
+ let previousTabIndex = (this.currentTab - 1) % this.tabs.length;
+ if (previousTabIndex < 0) {
+ previousTabIndex = this.tabs.length - 1;
+ }
+ this.tab = this.getTab(previousTabIndex);
+ break;
-// case 39: // right arrow
-// case 40: // down arrow
-// const nextTabIndex = (this.currentTab + 1) % this.tabs.length;
-// this.tab = this.getTab(nextTabIndex);
-// break;
+ case 39: // right arrow
+ case 40: // down arrow
+ const nextTabIndex = (this.currentTab + 1) % this.tabs.length;
+ this.tab = this.getTab(nextTabIndex);
+ break;
-// default:
-// }
-// }
+ default:
+ }
+ }
-// /**
-// * Return the tab associated to the index
-// * @private
-// * @param {number} tabIndex index of the tab
-// * @returns {Tab} tab
-// */
-// private getTab (tabIndex: number): Tab {
-// return this.tabs[tabIndex];
-// }
+ /**
+ * Return the tab associated to the index
+ * @private
+ * @param {number} tabIndex index of the tab
+ * @returns {Tab} tab
+ */
+ private getTab (tabIndex: number): Tab {
+ return this.tabs[tabIndex];
+ }
-// }
+}
diff --git a/src/assets/locale/zu.json b/src/assets/locale/zu.json
index 2cbf6509..7e9efe1c 100644
--- a/src/assets/locale/zu.json
+++ b/src/assets/locale/zu.json
@@ -398,5 +398,8 @@
"Add a new producer to the list": "Add a new producer to the list",
"Please select an existing report or upload a new one": "Please select an existing report or upload a new one",
"You will not be able to submit this observation to review with unknown operator selected": "You will not be able to submit this observation to review with unknown operator selected",
- "fmus": "FMUs"
+ "fmus": "FMUs",
+ "Document Type": "Document Type",
+ "Select a document type": "Select a document type",
+ "Please select a document type": "Please select a document type"
}
diff --git a/src/styles.scss b/src/styles.scss
index f06f4dbd..f396c2db 100644
--- a/src/styles.scss
+++ b/src/styles.scss
@@ -36,7 +36,7 @@
// @include foundation-reveal;
// @include foundation-switch;
@include foundation-table;
-// @include foundation-tabs;
+@include foundation-tabs;
// @include foundation-thumbnail;
// @include foundation-title-bar;
// @include foundation-tooltip;