From 16caaec0da50ae5207d9cf1a941f061341f658fb Mon Sep 17 00:00:00 2001 From: Alejandro Sanchez Date: Wed, 26 Jun 2024 21:53:31 -0700 Subject: [PATCH 01/10] Backend changes to support property locations per file --- .../api/Services/AcquisitionFileService.cs | 18 +++++---- .../backend/api/Services/IPropertyService.cs | 5 +++ .../backend/api/Services/PropertyService.cs | 40 +++++++++++++++++++ .../AcquisitionFilePropertyMap.cs | 2 + .../Models/Concepts/File/FilePropertyModel.cs | 7 +++- .../Models/Concepts/Property/GeometryModel.cs | 2 +- 6 files changed, 64 insertions(+), 10 deletions(-) diff --git a/source/backend/api/Services/AcquisitionFileService.cs b/source/backend/api/Services/AcquisitionFileService.cs index f48ecad9fb..5329a19f6a 100644 --- a/source/backend/api/Services/AcquisitionFileService.cs +++ b/source/backend/api/Services/AcquisitionFileService.cs @@ -282,7 +282,7 @@ public PimsAcquisitionFile Update(PimsAcquisitionFile acquisitionFile, IEnumerab public PimsAcquisitionFile UpdateProperties(PimsAcquisitionFile acquisitionFile, IEnumerable userOverrides) { - _logger.LogInformation("Updating acquisition file properties..."); + _logger.LogInformation("Updating acquisition file properties with AcquisitionFile id: {id}", acquisitionFile.Internal_Id); _user.ThrowIfNotAllAuthorized(Permissions.AcquisitionFileEdit, Permissions.PropertyView, Permissions.PropertyAdd); _user.ThrowInvalidAccessToAcquisitionFile(_userRepository, _acqFileRepository, acquisitionFile.Internal_Id); @@ -299,7 +299,7 @@ public PimsAcquisitionFile UpdateProperties(PimsAcquisitionFile acquisitionFile, } // Get the current properties in the research file - var currentProperties = _acquisitionFilePropertyRepository.GetPropertiesByAcquisitionFileId(acquisitionFile.Internal_Id); + var currentFileProperties = _acquisitionFilePropertyRepository.GetPropertiesByAcquisitionFileId(acquisitionFile.Internal_Id); // Check if the property is new or if it is being updated foreach (var incomingAcquisitionProperty in acquisitionFile.PimsPropertyAcquisitionFiles) @@ -307,22 +307,24 @@ public PimsAcquisitionFile UpdateProperties(PimsAcquisitionFile acquisitionFile, // If the property is not new, check if the name has been updated. if (incomingAcquisitionProperty.Internal_Id != 0) { - PimsPropertyAcquisitionFile existingProperty = currentProperties.FirstOrDefault(x => x.Internal_Id == incomingAcquisitionProperty.Internal_Id); - if (existingProperty.PropertyName != incomingAcquisitionProperty.PropertyName) + PimsPropertyAcquisitionFile existingFileProperty = currentFileProperties.FirstOrDefault(x => x.Internal_Id == incomingAcquisitionProperty.Internal_Id); + if (existingFileProperty.PropertyName != incomingAcquisitionProperty.PropertyName || !existingFileProperty.Location.EqualsExact(incomingAcquisitionProperty.Location)) { - existingProperty.PropertyName = incomingAcquisitionProperty.PropertyName; - _acquisitionFilePropertyRepository.Update(existingProperty); + existingFileProperty.PropertyName = incomingAcquisitionProperty.PropertyName; + _propertyService.UpdateFilePropertyLocation(incomingAcquisitionProperty, existingFileProperty); + _acquisitionFilePropertyRepository.Update(existingFileProperty); } } else { // New property needs to be added - _acquisitionFilePropertyRepository.Add(incomingAcquisitionProperty); + var newFileProperty = _propertyService.PopulateNewFileProperty(incomingAcquisitionProperty); + _acquisitionFilePropertyRepository.Add(newFileProperty); } } // The ones not on the new set should be deleted - List differenceSet = currentProperties.Where(x => !acquisitionFile.PimsPropertyAcquisitionFiles.Any(y => y.Internal_Id == x.Internal_Id)).ToList(); + List differenceSet = currentFileProperties.Where(x => !acquisitionFile.PimsPropertyAcquisitionFiles.Any(y => y.Internal_Id == x.Internal_Id)).ToList(); foreach (var deletedProperty in differenceSet) { var acqFileProperties = _acquisitionFilePropertyRepository.GetPropertiesByAcquisitionFileId(acquisitionFile.Internal_Id).FirstOrDefault(ap => ap.PropertyId == deletedProperty.PropertyId); diff --git a/source/backend/api/Services/IPropertyService.cs b/source/backend/api/Services/IPropertyService.cs index c826778e1b..b2b40d39fb 100644 --- a/source/backend/api/Services/IPropertyService.cs +++ b/source/backend/api/Services/IPropertyService.cs @@ -47,6 +47,11 @@ public interface IPropertyService void UpdateLocation(PimsProperty incomingProperty, ref PimsProperty propertyToUpdate, IEnumerable overrideCodes); + T PopulateNewFileProperty(T fileProperty); + + void UpdateFilePropertyLocation(T incomingFileProperty, T filePropertyToUpdate) + where T : IWithPropertyEntity; + IList GetHistoricalNumbersForPropertyId(long propertyId); IList UpdateHistoricalFileNumbers(long propertyId, IEnumerable pimsHistoricalNumbers); diff --git a/source/backend/api/Services/PropertyService.cs b/source/backend/api/Services/PropertyService.cs index 696eb9a711..969671c42d 100644 --- a/source/backend/api/Services/PropertyService.cs +++ b/source/backend/api/Services/PropertyService.cs @@ -377,6 +377,40 @@ public void UpdateLocation(PimsProperty incomingProperty, ref PimsProperty prope } } + public T PopulateNewFileProperty(T fileProperty) + { + // TODO: Remove this casting when LOCATION gets added to all remaining file-property types (research, disposition, lease) + if (fileProperty is PimsPropertyAcquisitionFile acquisitionFileProperty) + { + // convert spatial location from lat/long (4326) to BC Albers (3005) for database storage + var geom = acquisitionFileProperty.Location; + if (geom is not null && geom.SRID != SpatialReference.BCALBERS) + { + var newCoords = _coordinateService.TransformCoordinates(geom.SRID, SpatialReference.BCALBERS, geom.Coordinate); + acquisitionFileProperty.Location = GeometryHelper.CreatePoint(newCoords, SpatialReference.BCALBERS); + } + } + + return fileProperty; + } + + public void UpdateFilePropertyLocation(T incomingFileProperty, T filePropertyToUpdate) + where T : IWithPropertyEntity + { + // TODO: Remove this casting when LOCATION gets added to all remaining file-property types (research, disposition, lease) + if (incomingFileProperty is PimsPropertyAcquisitionFile incomingAcquisitionProperty + && filePropertyToUpdate is PimsPropertyAcquisitionFile acquisitionPropertyToUpdate) + { + // convert spatial location from lat/long (4326) to BC Albers (3005) for database storage + var geom = incomingAcquisitionProperty.Location; + if (geom is not null && geom.SRID != SpatialReference.BCALBERS) + { + var newCoords = _coordinateService.TransformCoordinates(geom.SRID, SpatialReference.BCALBERS, geom.Coordinate); + acquisitionPropertyToUpdate.Location = GeometryHelper.CreatePoint(newCoords, SpatialReference.BCALBERS); + } + } + } + public IList GetHistoricalNumbersForPropertyId(long propertyId) { @@ -415,6 +449,12 @@ public List TransformAllPropertiesToLatLong(List fileProperties) { foreach (var fileProperty in fileProperties) { + // TODO: Remove this casting when LOCATION gets added to all remaining file-property types (research, disposition, lease) + if (fileProperty is PimsPropertyAcquisitionFile acquisitionFileProperty && acquisitionFileProperty.Location is not null) + { + acquisitionFileProperty.Location = TransformCoordinates(acquisitionFileProperty.Location); + } + TransformPropertyToLatLong(fileProperty.Property); } diff --git a/source/backend/apimodels/Models/Concepts/AcquisitionFile/AcquisitionFilePropertyMap.cs b/source/backend/apimodels/Models/Concepts/AcquisitionFile/AcquisitionFilePropertyMap.cs index 438dc81333..7b13a6d484 100644 --- a/source/backend/apimodels/Models/Concepts/AcquisitionFile/AcquisitionFilePropertyMap.cs +++ b/source/backend/apimodels/Models/Concepts/AcquisitionFile/AcquisitionFilePropertyMap.cs @@ -13,6 +13,7 @@ public void Register(TypeAdapterConfig config) .Map(dest => dest.Id, src => src.PropertyAcquisitionFileId) .Map(dest => dest.PropertyName, src => src.PropertyName) .Map(dest => dest.DisplayOrder, src => src.DisplayOrder) + .Map(dest => dest.Location, src => src.Location) .Map(dest => dest.Property, src => src.Property) .Map(dest => dest.PropertyId, src => src.PropertyId) .Map(dest => dest.File, src => src.AcquisitionFile) @@ -27,6 +28,7 @@ public void Register(TypeAdapterConfig config) .Map(dest => dest.AcquisitionFileId, src => src.FileId) .Map(dest => dest.PropertyName, src => src.PropertyName) .Map(dest => dest.DisplayOrder, src => src.DisplayOrder) + .Map(dest => dest.Location, src => src.Location) .Inherits(); } } diff --git a/source/backend/apimodels/Models/Concepts/File/FilePropertyModel.cs b/source/backend/apimodels/Models/Concepts/File/FilePropertyModel.cs index f0e6be807a..e1722df790 100644 --- a/source/backend/apimodels/Models/Concepts/File/FilePropertyModel.cs +++ b/source/backend/apimodels/Models/Concepts/File/FilePropertyModel.cs @@ -13,10 +13,15 @@ public class FilePropertyModel : BaseConcurrentModel public long Id { get; set; } /// - /// get/set - The descriptive name of the property for this acquisition file. + /// get/set - The descriptive name of the property for this file. /// public string PropertyName { get; set; } + /// + /// get/set - The location of the property in the context of this file. + /// + public GeometryModel Location { get; set; } + /// /// get/set - The order to display the relationship. /// diff --git a/source/backend/apimodels/Models/Concepts/Property/GeometryModel.cs b/source/backend/apimodels/Models/Concepts/Property/GeometryModel.cs index 3269fdd33d..daf66d9225 100644 --- a/source/backend/apimodels/Models/Concepts/Property/GeometryModel.cs +++ b/source/backend/apimodels/Models/Concepts/Property/GeometryModel.cs @@ -5,7 +5,7 @@ public class GeometryModel #region Properties /// - /// get/set - The cordinate for the geometry. + /// get/set - The coordinate for the geometry. /// public CoordinateModel Coordinate { get; set; } From c7c0dcb918a735fbe0be05c308d17e4b9ef70415 Mon Sep 17 00:00:00 2001 From: Alejandro Sanchez Date: Thu, 27 Jun 2024 17:27:47 -0700 Subject: [PATCH 02/10] Fix null pointer error --- .../api/Services/AcquisitionFileService.cs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/source/backend/api/Services/AcquisitionFileService.cs b/source/backend/api/Services/AcquisitionFileService.cs index 5329a19f6a..824c2f1890 100644 --- a/source/backend/api/Services/AcquisitionFileService.cs +++ b/source/backend/api/Services/AcquisitionFileService.cs @@ -307,11 +307,24 @@ public PimsAcquisitionFile UpdateProperties(PimsAcquisitionFile acquisitionFile, // If the property is not new, check if the name has been updated. if (incomingAcquisitionProperty.Internal_Id != 0) { + var needsUpdate = false; PimsPropertyAcquisitionFile existingFileProperty = currentFileProperties.FirstOrDefault(x => x.Internal_Id == incomingAcquisitionProperty.Internal_Id); - if (existingFileProperty.PropertyName != incomingAcquisitionProperty.PropertyName || !existingFileProperty.Location.EqualsExact(incomingAcquisitionProperty.Location)) + if (existingFileProperty.PropertyName != incomingAcquisitionProperty.PropertyName) { existingFileProperty.PropertyName = incomingAcquisitionProperty.PropertyName; + needsUpdate = true; + } + + var incomingGeom = incomingAcquisitionProperty.Location; + var existingGeom = existingFileProperty.Location; + if (existingGeom is null || (incomingGeom is not null && !existingGeom.EqualsExact(incomingGeom))) + { _propertyService.UpdateFilePropertyLocation(incomingAcquisitionProperty, existingFileProperty); + needsUpdate = true; + } + + if (needsUpdate) + { _acquisitionFilePropertyRepository.Update(existingFileProperty); } } From 993d273f99705ff01ba3b58012266c836bda596a Mon Sep 17 00:00:00 2001 From: Alejandro Sanchez Date: Fri, 28 Jun 2024 09:15:23 -0700 Subject: [PATCH 03/10] Frontend changes --- .../src/components/common/mapFSM/useLocationFeatureLoader.tsx | 2 ++ source/frontend/src/components/propertySelector/models.ts | 2 ++ source/frontend/src/mocks/featureset.mock.ts | 4 ++++ source/frontend/src/utils/mapPropertyUtils.ts | 1 + 4 files changed, 9 insertions(+) diff --git a/source/frontend/src/components/common/mapFSM/useLocationFeatureLoader.tsx b/source/frontend/src/components/common/mapFSM/useLocationFeatureLoader.tsx index 215b59247e..980500cc85 100644 --- a/source/frontend/src/components/common/mapFSM/useLocationFeatureLoader.tsx +++ b/source/frontend/src/components/common/mapFSM/useLocationFeatureLoader.tsx @@ -16,6 +16,7 @@ import { PIMS_Property_Location_View } from '@/models/layers/pimsPropertyLocatio export interface LocationFeatureDataset { selectingComponentId: string | null; location: LatLngLiteral; + fileLocation: LatLngLiteral | null; pimsFeature: Feature | null; parcelFeature: Feature | null; regionFeature: Feature | null; @@ -44,6 +45,7 @@ const useLocationFeatureLoader = () => { const result: LocationFeatureDataset = { selectingComponentId: null, location: latLng, + fileLocation: latLng, pimsFeature: null, parcelFeature: null, regionFeature: null, diff --git a/source/frontend/src/components/propertySelector/models.ts b/source/frontend/src/components/propertySelector/models.ts index 41a19021bc..e8ae0e6786 100644 --- a/source/frontend/src/components/propertySelector/models.ts +++ b/source/frontend/src/components/propertySelector/models.ts @@ -1,4 +1,5 @@ import { MultiPolygon, Polygon } from 'geojson'; +import { LatLngLiteral } from 'leaflet'; import { AreaUnitTypes } from '@/constants'; @@ -8,6 +9,7 @@ export interface IMapProperty { pin?: string; latitude?: number; longitude?: number; + fileLocation?: LatLngLiteral; polygon?: Polygon | MultiPolygon; planNumber?: string; address?: string; diff --git a/source/frontend/src/mocks/featureset.mock.ts b/source/frontend/src/mocks/featureset.mock.ts index 357fcb0c80..f42b46e80c 100644 --- a/source/frontend/src/mocks/featureset.mock.ts +++ b/source/frontend/src/mocks/featureset.mock.ts @@ -6,6 +6,10 @@ export const getMockLocationFeatureDataset = (): LocationFeatureDataset => lat: 48.432802005, lng: -123.310041775, }, + fileLocation: { + lat: 48.432802005, + lng: -123.310041775, + }, pimsFeature: { properties: null, type: 'Feature', diff --git a/source/frontend/src/utils/mapPropertyUtils.ts b/source/frontend/src/utils/mapPropertyUtils.ts index 81e39dd555..d19d9daa8d 100644 --- a/source/frontend/src/utils/mapPropertyUtils.ts +++ b/source/frontend/src/utils/mapPropertyUtils.ts @@ -209,6 +209,7 @@ export function featuresetToMapProperty( pin: pin ?? undefined, latitude: featureSet?.location?.lat, longitude: featureSet?.location?.lng, + fileLocation: featureSet?.fileLocation ?? undefined, polygon: parcelFeature?.geometry?.type === ApiGen_CodeTypes_GeoJsonTypes.Polygon ? (parcelFeature.geometry as Polygon) From 8203d0c9f13613a54fe1ecbfb4128e8594d19772 Mon Sep 17 00:00:00 2001 From: Alejandro Sanchez Date: Fri, 28 Jun 2024 13:39:14 -0700 Subject: [PATCH 04/10] Regenerate TS api models --- .../src/models/api/generated/ApiGen_Concepts_FileProperty.ts | 2 ++ .../src/models/api/generated/ApiGen_Mayan_DocumentDetail.ts | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/source/frontend/src/models/api/generated/ApiGen_Concepts_FileProperty.ts b/source/frontend/src/models/api/generated/ApiGen_Concepts_FileProperty.ts index 7e66649250..304905a423 100644 --- a/source/frontend/src/models/api/generated/ApiGen_Concepts_FileProperty.ts +++ b/source/frontend/src/models/api/generated/ApiGen_Concepts_FileProperty.ts @@ -4,12 +4,14 @@ */ import { ApiGen_Base_BaseConcurrent } from './ApiGen_Base_BaseConcurrent'; import { ApiGen_Concepts_File } from './ApiGen_Concepts_File'; +import { ApiGen_Concepts_Geometry } from './ApiGen_Concepts_Geometry'; import { ApiGen_Concepts_Property } from './ApiGen_Concepts_Property'; // LINK: @backend/apimodels/Models/Concepts/File/FilePropertyModel.cs export interface ApiGen_Concepts_FileProperty extends ApiGen_Base_BaseConcurrent { id: number; propertyName: string | null; + location: ApiGen_Concepts_Geometry | null; displayOrder: number | null; property: ApiGen_Concepts_Property | null; propertyId: number; diff --git a/source/frontend/src/models/api/generated/ApiGen_Mayan_DocumentDetail.ts b/source/frontend/src/models/api/generated/ApiGen_Mayan_DocumentDetail.ts index d84a6ce5da..0d6a534aeb 100644 --- a/source/frontend/src/models/api/generated/ApiGen_Mayan_DocumentDetail.ts +++ b/source/frontend/src/models/api/generated/ApiGen_Mayan_DocumentDetail.ts @@ -17,5 +17,4 @@ export interface ApiGen_Mayan_DocumentDetail { uuid: string | null; file_latest: ApiGen_Mayan_FileLatest | null; document_type: ApiGen_Mayan_DocumentType | null; - file: ApiGen_Mayan_FileLatest | null; } From 72c36abdf0a52a3ada1a01408b89c1bef0396bab Mon Sep 17 00:00:00 2001 From: Alejandro Sanchez Date: Fri, 28 Jun 2024 17:19:48 -0700 Subject: [PATCH 05/10] Update file models with marker location per file --- source/frontend/src/features/leases/models.ts | 1 + .../mapSideBar/acquisition/add/models.ts | 27 ++++++++------ .../models/DispositionFormModel.ts | 27 ++++++++------ .../tabs/propertyResearch/update/models.ts | 4 +-- .../mapSideBar/research/add/models.ts | 36 ++++++++++--------- .../src/features/mapSideBar/shared/models.ts | 22 ++++++++---- source/frontend/src/utils/mapPropertyUtils.ts | 13 ++++++- 7 files changed, 83 insertions(+), 47 deletions(-) diff --git a/source/frontend/src/features/leases/models.ts b/source/frontend/src/features/leases/models.ts index 9453316ebe..3de0a0f711 100644 --- a/source/frontend/src/features/leases/models.ts +++ b/source/frontend/src/features/leases/models.ts @@ -245,6 +245,7 @@ export class FormLeaseProperty { ? toTypeCodeNullable(formLeaseProperty.areaUnitTypeCode) ?? null : null, displayOrder: null, + location: null, // TODO: Add proper file location values when DB schema gets added ...getEmptyBaseAudit(formLeaseProperty.rowVersion), }; } diff --git a/source/frontend/src/features/mapSideBar/acquisition/add/models.ts b/source/frontend/src/features/mapSideBar/acquisition/add/models.ts index d08b1b216a..89975cd409 100644 --- a/source/frontend/src/features/mapSideBar/acquisition/add/models.ts +++ b/source/frontend/src/features/mapSideBar/acquisition/add/models.ts @@ -4,6 +4,7 @@ import { ApiGen_Concepts_AcquisitionFile } from '@/models/api/generated/ApiGen_C import { ApiGen_Concepts_AcquisitionFileOwner } from '@/models/api/generated/ApiGen_Concepts_AcquisitionFileOwner'; import { ApiGen_Concepts_AcquisitionFileProperty } from '@/models/api/generated/ApiGen_Concepts_AcquisitionFileProperty'; import { getEmptyBaseAudit } from '@/models/defaultInitializers'; +import { latLngToApiLocation } from '@/utils'; import { fromTypeCode, stringToNumberOrNull, toTypeCodeNullable } from '@/utils/formUtils'; import { exists, isValidId, isValidIsoDateTime } from '@/utils/utils'; @@ -62,17 +63,7 @@ export class AcquisitionForm implements WithAcquisitionTeam, WithAcquisitionOwne fundingTypeCode: toTypeCodeNullable(this.fundingTypeCode), fundingOther: this.fundingTypeOtherDescription, // ACQ file properties - fileProperties: this.properties.map(ap => ({ - id: ap.id ?? 0, - propertyName: ap.name ?? null, - displayOrder: ap.displayOrder ?? null, - rowVersion: ap.rowVersion ?? null, - property: ap.toApi(), - propertyId: ap.apiId ?? 0, - fileId: this.id ?? 0, - acquisitionFile: null, - file: null, - })), + fileProperties: this.properties.map(x => this.toPropertyApi(x)), acquisitionFileOwners: this.owners .filter(x => !x.isEmpty()) .map(x => x.toApi()), @@ -95,6 +86,20 @@ export class AcquisitionForm implements WithAcquisitionTeam, WithAcquisitionOwne }; } + private toPropertyApi(x: PropertyForm): ApiGen_Concepts_AcquisitionFileProperty { + return { + id: x.id ?? 0, + fileId: this.id ?? 0, + property: x.toApi(), + propertyId: x.apiId ?? 0, + propertyName: x.name ?? null, + location: latLngToApiLocation(x.fileLocation?.lat, x.fileLocation?.lng), + displayOrder: x.displayOrder ?? null, + rowVersion: x.rowVersion ?? null, + file: null, + }; + } + static fromApi(model: ApiGen_Concepts_AcquisitionFile): AcquisitionForm { const newForm = new AcquisitionForm(); newForm.id = model.id; diff --git a/source/frontend/src/features/mapSideBar/disposition/models/DispositionFormModel.ts b/source/frontend/src/features/mapSideBar/disposition/models/DispositionFormModel.ts index 6fb77c2464..5519190eba 100644 --- a/source/frontend/src/features/mapSideBar/disposition/models/DispositionFormModel.ts +++ b/source/frontend/src/features/mapSideBar/disposition/models/DispositionFormModel.ts @@ -2,6 +2,7 @@ import { IAutocompletePrediction } from '@/interfaces/IAutocomplete'; import { ApiGen_Concepts_DispositionFile } from '@/models/api/generated/ApiGen_Concepts_DispositionFile'; import { ApiGen_Concepts_DispositionFileProperty } from '@/models/api/generated/ApiGen_Concepts_DispositionFileProperty'; import { getEmptyBaseAudit } from '@/models/defaultInitializers'; +import { latLngToApiLocation } from '@/utils'; import { emptyStringtoNullable, fromTypeCode, toTypeCodeNullable } from '@/utils/formUtils'; import { exists, isValidIsoDateTime } from '@/utils/utils'; @@ -83,17 +84,7 @@ export class DispositionFormModel implements WithDispositionTeam { .filter(x => !!x.contact && !!x.teamProfileTypeCode) .map(x => x.toApi(this.id || 0)) .filter(exists), - fileProperties: this.fileProperties.map(ap => ({ - id: ap.id ?? 0, - propertyName: ap.name ?? null, - displayOrder: ap.displayOrder ?? null, - rowVersion: ap.rowVersion ?? null, - property: ap.toApi(), - propertyId: ap.apiId ?? 0, - file: null, - fileId: 0, - })), - + fileProperties: this.fileProperties.map(x => this.toPropertyApi(x)), dispositionOffers: this.offers.map(x => x.toApi()), dispositionSale: this.sale ? this.sale.toApi() : null, dispositionAppraisal: this.appraisal ? this.appraisal.toApi() : null, @@ -102,6 +93,20 @@ export class DispositionFormModel implements WithDispositionTeam { }; } + private toPropertyApi(x: PropertyForm): ApiGen_Concepts_DispositionFileProperty { + return { + id: x.id ?? 0, + fileId: this.id ?? 0, + property: x.toApi(), + propertyId: x.apiId ?? 0, + propertyName: x.name ?? null, + location: latLngToApiLocation(x.fileLocation?.lat, x.fileLocation?.lng), + displayOrder: x.displayOrder ?? null, + rowVersion: x.rowVersion ?? null, + file: null, + }; + } + static fromApi(model: ApiGen_Concepts_DispositionFile): DispositionFormModel { const dispositionForm = new DispositionFormModel( model.id, diff --git a/source/frontend/src/features/mapSideBar/property/tabs/propertyResearch/update/models.ts b/source/frontend/src/features/mapSideBar/property/tabs/propertyResearch/update/models.ts index 9a3e7c26e2..47ea175c7a 100644 --- a/source/frontend/src/features/mapSideBar/property/tabs/propertyResearch/update/models.ts +++ b/source/frontend/src/features/mapSideBar/property/tabs/propertyResearch/update/models.ts @@ -1,9 +1,8 @@ import { ApiGen_Concepts_PropertyPurpose } from '@/models/api/generated/ApiGen_Concepts_PropertyPurpose'; import { ApiGen_Concepts_ResearchFileProperty } from '@/models/api/generated/ApiGen_Concepts_ResearchFileProperty'; +import { getEmptyResearchFile } from '@/models/defaultInitializers'; import { exists } from '@/utils/utils'; -import { getEmptyResearchFile } from './../../../../../../models/defaultInitializers'; - export class PropertyResearchFilePurposeFormModel { public id?: number; public propertyPurposeTypeCode?: string; @@ -101,6 +100,7 @@ export class UpdatePropertyFormModel { documentReference: this.documentReference ?? null, researchSummary: this.researchSummary ?? null, property: null, + location: null, // TODO: Add proper file location values when DB schema gets added fileId: this.researchFileId ?? 0, file: { ...getEmptyResearchFile(), rowVersion: this.researchFileRowVersion }, purposeTypes: this.purposeTypes?.map(x => x.toApi()) ?? null, diff --git a/source/frontend/src/features/mapSideBar/research/add/models.ts b/source/frontend/src/features/mapSideBar/research/add/models.ts index ef38fd01cb..dc89e21ed2 100644 --- a/source/frontend/src/features/mapSideBar/research/add/models.ts +++ b/source/frontend/src/features/mapSideBar/research/add/models.ts @@ -1,6 +1,7 @@ import { ApiGen_Concepts_ResearchFile } from '@/models/api/generated/ApiGen_Concepts_ResearchFile'; import { ApiGen_Concepts_ResearchFileProperty } from '@/models/api/generated/ApiGen_Concepts_ResearchFileProperty'; import { getEmptyBaseAudit } from '@/models/defaultInitializers'; +import { latLngToApiLocation } from '@/utils'; import { PropertyForm } from '../../shared/models'; import { ResearchFileProjectFormModel } from '../common/models'; @@ -22,22 +23,7 @@ export class ResearchForm { return { id: this.id ?? 0, fileName: this.name, - fileProperties: this.properties.map(x => ({ - id: x.id ?? 0, - property: x.toApi(), - propertyId: x.apiId ?? 0, - researchFile: { id: this.id }, - propertyName: x.name ?? null, - rowVersion: x.rowVersion ?? null, - displayOrder: null, - documentReference: null, - file: null, - fileId: this.id ?? 0, - isLegalOpinionObtained: null, - isLegalOpinionRequired: null, - purposeTypes: null, - researchSummary: null, - })), + fileProperties: this.properties.map(x => this.toPropertyApi(x)), researchFileProjects: ResearchFileProjectFormModel.toApiList(this.researchFileProjects), ...getEmptyBaseAudit(this.rowVersion), expropriationNotes: null, @@ -58,6 +44,24 @@ export class ResearchForm { }; } + private toPropertyApi(x: PropertyForm): ApiGen_Concepts_ResearchFileProperty { + return { + id: x.id ?? 0, + property: x.toApi(), + propertyId: x.apiId ?? 0, + propertyName: x.name ?? null, + rowVersion: x.rowVersion ?? null, + displayOrder: x.displayOrder ?? null, + location: latLngToApiLocation(x.fileLocation?.lat, x.fileLocation?.lng), + documentReference: null, + file: null, + fileId: this.id ?? 0, + isLegalOpinionObtained: null, + isLegalOpinionRequired: null, + purposeTypes: null, + researchSummary: null, + }; + } public static fromApi(model: ApiGen_Concepts_ResearchFile): ResearchForm { const newForm = new ResearchForm(); newForm.id = model.id; diff --git a/source/frontend/src/features/mapSideBar/shared/models.ts b/source/frontend/src/features/mapSideBar/shared/models.ts index fbf2e1aa0b..e1c35d7ba8 100644 --- a/source/frontend/src/features/mapSideBar/shared/models.ts +++ b/source/frontend/src/features/mapSideBar/shared/models.ts @@ -1,4 +1,5 @@ import { MultiPolygon, Polygon } from 'geojson'; +import { LatLngLiteral } from 'leaflet'; import { isNumber } from 'lodash'; import { LocationFeatureDataset } from '@/components/common/mapFSM/useLocationFeatureLoader'; @@ -21,6 +22,8 @@ import { exists, formatApiAddress, formatBcaAddress, + getLatLng, + latLngToApiLocation, pidFromFeatureSet, pidParser, pinFromFeatureSet, @@ -55,6 +58,7 @@ export class FileForm { property: x.toApi(), propertyId: x.apiId ?? 0, propertyName: x.name ?? null, + location: latLngToApiLocation(x.fileLocation?.lat, x.fileLocation?.lng), rowVersion: x.rowVersion ?? null, displayOrder: null, file: null, @@ -80,6 +84,7 @@ export class PropertyForm { public pin?: string; public latitude?: number; public longitude?: number; + public fileLocation?: LatLngLiteral; public polygon?: Polygon | MultiPolygon; public planNumber?: string; public name?: string; @@ -109,6 +114,7 @@ export class PropertyForm { pin: model.pin, latitude: model.latitude, longitude: model.longitude, + fileLocation: model.fileLocation, polygon: model.polygon, planNumber: model.planNumber, region: model.region, @@ -124,14 +130,15 @@ export class PropertyForm { public static fromFeatureDataset(model: LocationFeatureDataset): PropertyForm { return new PropertyForm({ - apiId: +(model.pimsFeature?.properties?.PROPERTY_ID ?? 0), + apiId: +(model?.pimsFeature?.properties?.PROPERTY_ID ?? 0), pid: pidFromFeatureSet(model), pin: pinFromFeatureSet(model), - latitude: model.location?.lat, - longitude: model.location?.lng, + latitude: model?.location?.lat, + longitude: model?.location?.lng, + fileLocation: model?.fileLocation ?? model?.location ?? undefined, planNumber: - model.pimsFeature?.properties?.SURVEY_PLAN_NUMBER ?? - model.parcelFeature?.properties?.PLAN_NUMBER ?? + model?.pimsFeature?.properties?.SURVEY_PLAN_NUMBER ?? + model?.parcelFeature?.properties?.PLAN_NUMBER ?? '', polygon: model?.parcelFeature?.geometry?.type === ApiGen_CodeTypes_GeoJsonTypes.Polygon @@ -165,6 +172,7 @@ export class PropertyForm { pin: this.pin, latitude: this.latitude, longitude: this.longitude, + fileLocation: this.fileLocation, planNumber: this.planNumber, polygon: this.polygon, region: this.region, @@ -205,6 +213,7 @@ export class PropertyForm { geometry: this.polygon ? this.polygon : null, }, location: { lat: this.latitude, lng: this.longitude }, + fileLocation: this.fileLocation ?? { lat: this.latitude, lng: this.longitude }, regionFeature: { properties: { REGION_NAME: this.regionName, @@ -245,6 +254,7 @@ export class PropertyForm { newForm.pin = model.property?.pin?.toString(); newForm.latitude = model.property?.latitude ?? undefined; newForm.longitude = model.property?.longitude ?? undefined; + newForm.fileLocation = getLatLng(model.location) ?? undefined; newForm.planNumber = model.property?.planNumber ?? undefined; newForm.region = model.property?.region?.id ?? undefined; newForm.district = model.property?.district?.id ?? undefined; @@ -295,7 +305,7 @@ export class PropertyForm { pid: pidParser(this.pid) ?? null, pin: this.pin !== undefined ? Number(this.pin) : null, planNumber: this.planNumber ?? null, - location: { coordinate: { x: this.longitude ?? 0, y: this.latitude ?? 0 } }, + location: latLngToApiLocation(this.latitude, this.longitude), boundary: this.polygon ? this.polygon : null, region: toTypeCodeNullable(this.region), district: toTypeCodeNullable(this.district), diff --git a/source/frontend/src/utils/mapPropertyUtils.ts b/source/frontend/src/utils/mapPropertyUtils.ts index d19d9daa8d..9aac704091 100644 --- a/source/frontend/src/utils/mapPropertyUtils.ts +++ b/source/frontend/src/utils/mapPropertyUtils.ts @@ -76,6 +76,16 @@ export const getLatLng = ( return null; }; +export function latLngToApiLocation( + latitude?: number, + longitude?: number, +): ApiGen_Concepts_Geometry | null { + if (isNumber(latitude) && isNumber(longitude)) { + return { coordinate: { x: longitude, y: latitude } }; + } + return null; +} + export const getFilePropertyName = ( fileProperty: ApiGen_Concepts_FileProperty | undefined | null, skipName = false, @@ -172,6 +182,7 @@ function toMapProperty( pin: feature?.properties?.PIN?.toString() ?? undefined, latitude: latitude, longitude: longitude, + fileLocation: { lat: latitude, lng: longitude }, planNumber: feature?.properties?.PLAN_NUMBER?.toString() ?? undefined, address: address, legalDescription: feature?.properties?.LEGAL_DESCRIPTION, @@ -209,7 +220,7 @@ export function featuresetToMapProperty( pin: pin ?? undefined, latitude: featureSet?.location?.lat, longitude: featureSet?.location?.lng, - fileLocation: featureSet?.fileLocation ?? undefined, + fileLocation: featureSet?.fileLocation ?? featureSet?.location ?? undefined, polygon: parcelFeature?.geometry?.type === ApiGen_CodeTypes_GeoJsonTypes.Polygon ? (parcelFeature.geometry as Polygon) From 05a1905bec21db79e5cea3e4c8f33dc17ad1d690 Mon Sep 17 00:00:00 2001 From: Alejandro Sanchez Date: Fri, 28 Jun 2024 17:21:01 -0700 Subject: [PATCH 06/10] Update mocks --- source/frontend/src/mocks/acquisitionFiles.mock.ts | 2 ++ source/frontend/src/mocks/documents.mock.ts | 11 ----------- source/frontend/src/mocks/fileProperty.mock.ts | 1 + source/frontend/src/mocks/properties.mock.ts | 3 +++ source/frontend/src/mocks/researchFile.mock.ts | 1 + 5 files changed, 7 insertions(+), 11 deletions(-) diff --git a/source/frontend/src/mocks/acquisitionFiles.mock.ts b/source/frontend/src/mocks/acquisitionFiles.mock.ts index 07a6a1b35d..f6be177da2 100644 --- a/source/frontend/src/mocks/acquisitionFiles.mock.ts +++ b/source/frontend/src/mocks/acquisitionFiles.mock.ts @@ -112,6 +112,7 @@ export const mockAcquisitionFileResponse = ( fileId: 1, file: null, propertyName: null, + location: null, rowVersion: 1, }, { @@ -156,6 +157,7 @@ export const mockAcquisitionFileResponse = ( fileId: 1, file: null, propertyName: null, + location: null, }, ], acquisitionTeam: [ diff --git a/source/frontend/src/mocks/documents.mock.ts b/source/frontend/src/mocks/documents.mock.ts index 4a7864a9f8..161ff031f4 100644 --- a/source/frontend/src/mocks/documents.mock.ts +++ b/source/frontend/src/mocks/documents.mock.ts @@ -221,17 +221,6 @@ export const mockDocumentMetadata = (): ApiGen_Mayan_DocumentMetadata[] => [ label: '', datetime_created: '2022-07-27T16:06:42.42', description: '', - file: { - id: 2, - comment: '', - encoding: '', - filename: '', - mimetype: '', - size: 12, - timestamp: '', - file: '', - checksum: '', - }, file_latest: { id: 2, comment: '', diff --git a/source/frontend/src/mocks/fileProperty.mock.ts b/source/frontend/src/mocks/fileProperty.mock.ts index fd38c572a2..bb3d953470 100644 --- a/source/frontend/src/mocks/fileProperty.mock.ts +++ b/source/frontend/src/mocks/fileProperty.mock.ts @@ -10,6 +10,7 @@ export const getEmptyFileProperty = (): ApiGen_Concepts_FileProperty => { propertyId: 0, fileId: 0, file: null, + location: null, ...getEmptyBaseAudit(), }; }; diff --git a/source/frontend/src/mocks/properties.mock.ts b/source/frontend/src/mocks/properties.mock.ts index ffd1e4c5da..2e64f45353 100644 --- a/source/frontend/src/mocks/properties.mock.ts +++ b/source/frontend/src/mocks/properties.mock.ts @@ -307,6 +307,7 @@ export const getMockApiPropertyFiles = (): ApiGen_Concepts_FileProperty[] => [ rowVersion: 3, }, displayOrder: null, + location: null, rowVersion: null, }, { @@ -351,6 +352,7 @@ export const getMockApiPropertyFiles = (): ApiGen_Concepts_FileProperty[] => [ }, displayOrder: null, propertyName: null, + location: null, rowVersion: null, }, ]; @@ -366,6 +368,7 @@ export const getEmptyPropertyLease = (): ApiGen_Concepts_PropertyLease => { displayOrder: null, property: null, propertyId: 0, + location: null, rowVersion: null, }; }; diff --git a/source/frontend/src/mocks/researchFile.mock.ts b/source/frontend/src/mocks/researchFile.mock.ts index 423225ce94..92db0c2d06 100644 --- a/source/frontend/src/mocks/researchFile.mock.ts +++ b/source/frontend/src/mocks/researchFile.mock.ts @@ -65,6 +65,7 @@ export const getMockResearchFile = (): ApiGen_Concepts_ResearchFile => ({ documentReference: null, isLegalOpinionObtained: null, file: null, + location: null, }, ], requestDate: '2022-04-14T00:00:00', From 721e8bd9290a66ef492d36acb87dbbb59babda4d Mon Sep 17 00:00:00 2001 From: Alejandro Sanchez Date: Fri, 28 Jun 2024 17:22:31 -0700 Subject: [PATCH 07/10] Test updates --- .../leaflet/LayerPopup/LayerPopupView.test.tsx | 10 ++++++++-- .../search/PropertySelectorSearchContainer.tsx | 9 +-------- .../disposition/list/DispositionListView.test.tsx | 1 + .../DispositionSearchResults.test.tsx | 3 +++ .../documentDetail/DocumentDetailForm.test.tsx | 14 -------------- .../documentDetail/DocumentDetailView.test.tsx | 11 ----------- .../leases/detail/LeaseHeaderAddresses.test.tsx | 5 +++++ .../detail/LeasePages/surplus/Surplus.test.tsx | 3 +++ .../add/AddAcquisitionContainer.test.tsx | 2 ++ .../GenerateForm/hooks/useGenerateH0443.test.tsx | 2 ++ .../detail/PropertyResearchTabView.test.tsx | 3 ++- .../update/UpdatePropertyForm.test.tsx | 1 + .../research/add/AddResearchContainer.test.tsx | 1 + .../update/properties/UpdateProperties.test.tsx | 1 + .../research/list/ResearchListView.test.tsx | 2 ++ 15 files changed, 32 insertions(+), 36 deletions(-) diff --git a/source/frontend/src/components/maps/leaflet/LayerPopup/LayerPopupView.test.tsx b/source/frontend/src/components/maps/leaflet/LayerPopup/LayerPopupView.test.tsx index 1b701d6e36..ff7e4d491b 100644 --- a/source/frontend/src/components/maps/leaflet/LayerPopup/LayerPopupView.test.tsx +++ b/source/frontend/src/components/maps/leaflet/LayerPopup/LayerPopupView.test.tsx @@ -86,6 +86,7 @@ describe('LayerPopupView component', () => { geometry: { type: 'Point', coordinates: [] }, }, location: { lat: 0, lng: 0 }, + fileLocation: null, parcelFeature: null, regionFeature: null, districtFeature: null, @@ -112,6 +113,7 @@ describe('LayerPopupView component', () => { geometry: { type: 'Point', coordinates: [] }, }, location: { lat: 0, lng: 0 }, + fileLocation: null, pimsFeature: null, regionFeature: null, districtFeature: null, @@ -139,6 +141,7 @@ describe('LayerPopupView component', () => { geometry: { type: 'Point', coordinates: [] }, }, location: { lat: 0, lng: 0 }, + fileLocation: null, pimsFeature: { type: 'Feature', properties: null as any, @@ -184,12 +187,13 @@ describe('LayerPopupView component', () => { expect(history.location.pathname).toBe('/mapview/sidebar/acquisition/new'); }); - it('Hides subdivision and consolidation if not in the pims system', async () => { + it('hides subdivision and consolidation if not in the pims system', async () => { const { getByTestId, getByText, queryByText } = setup({ layerPopup: { data: {} } as any, featureDataset: { pimsFeature: null, location: { lat: 0, lng: 0 }, + fileLocation: null, parcelFeature: null, regionFeature: null, districtFeature: null, @@ -206,7 +210,7 @@ describe('LayerPopupView component', () => { expect(consolidationLink).not.toBeInTheDocument(); }); - it('handles create create subdivision action', async () => { + it('handles create subdivision action', async () => { const propertyId = 1; const { getByTestId, getByText } = setup({ @@ -218,6 +222,7 @@ describe('LayerPopupView component', () => { geometry: { type: 'Point', coordinates: [] }, }, location: { lat: 0, lng: 0 }, + fileLocation: null, parcelFeature: null, regionFeature: null, districtFeature: null, @@ -245,6 +250,7 @@ describe('LayerPopupView component', () => { geometry: { type: 'Point', coordinates: [] }, }, location: { lat: 0, lng: 0 }, + fileLocation: null, parcelFeature: null, regionFeature: null, districtFeature: null, diff --git a/source/frontend/src/components/propertySelector/search/PropertySelectorSearchContainer.tsx b/source/frontend/src/components/propertySelector/search/PropertySelectorSearchContainer.tsx index a0a3f8c95f..7a02fbe5c3 100644 --- a/source/frontend/src/components/propertySelector/search/PropertySelectorSearchContainer.tsx +++ b/source/frontend/src/components/propertySelector/search/PropertySelectorSearchContainer.tsx @@ -207,14 +207,7 @@ export const PropertySelectorSearchContainer: React.FC, -) => { +export const featureToLocationFeatureDataset = (feature: Feature) => { const center = getFeatureBoundedCenter(feature); return { parcelFeature: feature, diff --git a/source/frontend/src/features/disposition/list/DispositionListView.test.tsx b/source/frontend/src/features/disposition/list/DispositionListView.test.tsx index dd2c65b110..f59b7b6cc2 100644 --- a/source/frontend/src/features/disposition/list/DispositionListView.test.tsx +++ b/source/frontend/src/features/disposition/list/DispositionListView.test.tsx @@ -121,6 +121,7 @@ describe('Disposition List View', () => { displayOrder: null, file: null, propertyName: null, + location: null, rowVersion: null, }, ], diff --git a/source/frontend/src/features/disposition/list/DispositionSearchResults/DispositionSearchResults.test.tsx b/source/frontend/src/features/disposition/list/DispositionSearchResults/DispositionSearchResults.test.tsx index 6dafee09ec..7c2e422ef7 100644 --- a/source/frontend/src/features/disposition/list/DispositionSearchResults/DispositionSearchResults.test.tsx +++ b/source/frontend/src/features/disposition/list/DispositionSearchResults/DispositionSearchResults.test.tsx @@ -89,6 +89,7 @@ describe('Disposition search results table', () => { displayOrder: null, file: null, propertyName: null, + location: null, rowVersion: null, }, { @@ -99,6 +100,7 @@ describe('Disposition search results table', () => { displayOrder: null, file: null, propertyName: null, + location: null, rowVersion: null, }, { @@ -109,6 +111,7 @@ describe('Disposition search results table', () => { displayOrder: null, file: null, propertyName: null, + location: null, rowVersion: null, }, ], diff --git a/source/frontend/src/features/documents/documentDetail/DocumentDetailForm.test.tsx b/source/frontend/src/features/documents/documentDetail/DocumentDetailForm.test.tsx index 3e1ee457f3..4f3b31e40b 100644 --- a/source/frontend/src/features/documents/documentDetail/DocumentDetailForm.test.tsx +++ b/source/frontend/src/features/documents/documentDetail/DocumentDetailForm.test.tsx @@ -70,20 +70,6 @@ const documentMetadata: ApiGen_Mayan_DocumentMetadata[] = [ label: '', datetime_created: '2022-07-27T16:06:42.42', description: '', - file: { - id: 2, - - comment: '', - encoding: '', - - mimetype: '', - size: 12, - - filename: null, - timestamp: '', - checksum: '', - file: '', - }, language: '', uuid: '', file_latest: { diff --git a/source/frontend/src/features/documents/documentDetail/DocumentDetailView.test.tsx b/source/frontend/src/features/documents/documentDetail/DocumentDetailView.test.tsx index 3c966c296c..2079c89dc0 100644 --- a/source/frontend/src/features/documents/documentDetail/DocumentDetailView.test.tsx +++ b/source/frontend/src/features/documents/documentDetail/DocumentDetailView.test.tsx @@ -52,17 +52,6 @@ const documentTypeMetadata: ApiGen_Mayan_DocumentMetadata[] = [ description: '', language: '', uuid: '', - file: { - id: 2, - comment: '', - encoding: '', - filename: '', - mimetype: '', - size: 12, - timestamp: '', - checksum: '', - file: '', - }, file_latest: { id: 2, comment: '', diff --git a/source/frontend/src/features/leases/detail/LeaseHeaderAddresses.test.tsx b/source/frontend/src/features/leases/detail/LeaseHeaderAddresses.test.tsx index f18ab83aaf..71a35ca5c7 100644 --- a/source/frontend/src/features/leases/detail/LeaseHeaderAddresses.test.tsx +++ b/source/frontend/src/features/leases/detail/LeaseHeaderAddresses.test.tsx @@ -65,6 +65,7 @@ describe('LeaseHeaderAddresses component', () => { id: 0, propertyId: 0, propertyName: null, + location: null, rowVersion: null, }, { @@ -77,6 +78,7 @@ describe('LeaseHeaderAddresses component', () => { id: 0, propertyId: 0, propertyName: null, + location: null, rowVersion: null, }, { @@ -89,6 +91,7 @@ describe('LeaseHeaderAddresses component', () => { id: 0, propertyId: 0, propertyName: null, + location: null, rowVersion: null, }, { @@ -101,6 +104,7 @@ describe('LeaseHeaderAddresses component', () => { id: 0, propertyId: 0, propertyName: null, + location: null, rowVersion: null, }, { @@ -113,6 +117,7 @@ describe('LeaseHeaderAddresses component', () => { id: 0, propertyId: 0, propertyName: null, + location: null, rowVersion: null, }, ], diff --git a/source/frontend/src/features/leases/detail/LeasePages/surplus/Surplus.test.tsx b/source/frontend/src/features/leases/detail/LeasePages/surplus/Surplus.test.tsx index 3aad54c314..ea545c79cb 100644 --- a/source/frontend/src/features/leases/detail/LeasePages/surplus/Surplus.test.tsx +++ b/source/frontend/src/features/leases/detail/LeasePages/surplus/Surplus.test.tsx @@ -70,6 +70,7 @@ describe('Lease Surplus Declaration', () => { id: 0, propertyId: 0, propertyName: null, + location: null, rowVersion: null, }, ], @@ -103,6 +104,7 @@ describe('Lease Surplus Declaration', () => { id: 0, propertyId: 0, propertyName: null, + location: null, rowVersion: null, }, ], @@ -144,6 +146,7 @@ describe('Lease Surplus Declaration', () => { id: 0, propertyId: 0, propertyName: null, + location: null, rowVersion: null, }, ], diff --git a/source/frontend/src/features/mapSideBar/acquisition/add/AddAcquisitionContainer.test.tsx b/source/frontend/src/features/mapSideBar/acquisition/add/AddAcquisitionContainer.test.tsx index 8c8c90e226..ec7f1cf141 100644 --- a/source/frontend/src/features/mapSideBar/acquisition/add/AddAcquisitionContainer.test.tsx +++ b/source/frontend/src/features/mapSideBar/acquisition/add/AddAcquisitionContainer.test.tsx @@ -230,6 +230,7 @@ describe('AddAcquisitionContainer component', () => { ...mapMachineBaseMock, selectedFeatureDataset: { location: { lng: -120.69195885, lat: 50.25163372 }, + fileLocation: null, pimsFeature: null, parcelFeature: null, regionFeature: { @@ -258,6 +259,7 @@ describe('AddAcquisitionContainer component', () => { ...mapMachineBaseMock, selectedFeatureDataset: { location: { lng: -120.69195885, lat: 50.25163372 }, + fileLocation: null, pimsFeature: null, parcelFeature: null, regionFeature: { diff --git a/source/frontend/src/features/mapSideBar/acquisition/common/GenerateForm/hooks/useGenerateH0443.test.tsx b/source/frontend/src/features/mapSideBar/acquisition/common/GenerateForm/hooks/useGenerateH0443.test.tsx index c1607c0a43..fd89ee6abf 100644 --- a/source/frontend/src/features/mapSideBar/acquisition/common/GenerateForm/hooks/useGenerateH0443.test.tsx +++ b/source/frontend/src/features/mapSideBar/acquisition/common/GenerateForm/hooks/useGenerateH0443.test.tsx @@ -283,6 +283,7 @@ describe('useGenerateH0443 functions', () => { id: 0, property: null, propertyName: null, + location: null, rowVersion: null, }, { @@ -293,6 +294,7 @@ describe('useGenerateH0443 functions', () => { id: 0, property: null, propertyName: null, + location: null, rowVersion: null, }, ], diff --git a/source/frontend/src/features/mapSideBar/property/tabs/propertyResearch/detail/PropertyResearchTabView.test.tsx b/source/frontend/src/features/mapSideBar/property/tabs/propertyResearch/detail/PropertyResearchTabView.test.tsx index 61c52e0b12..9843fa2e10 100644 --- a/source/frontend/src/features/mapSideBar/property/tabs/propertyResearch/detail/PropertyResearchTabView.test.tsx +++ b/source/frontend/src/features/mapSideBar/property/tabs/propertyResearch/detail/PropertyResearchTabView.test.tsx @@ -72,7 +72,8 @@ const fakePropertyResearch: ApiGen_Concepts_ResearchFileProperty = { rowVersion: null, }, ], - displayOrder: null, fileId: 0, + displayOrder: null, + location: null, rowVersion: null, }; diff --git a/source/frontend/src/features/mapSideBar/property/tabs/propertyResearch/update/UpdatePropertyForm.test.tsx b/source/frontend/src/features/mapSideBar/property/tabs/propertyResearch/update/UpdatePropertyForm.test.tsx index 6e452bb597..39648bd817 100644 --- a/source/frontend/src/features/mapSideBar/property/tabs/propertyResearch/update/UpdatePropertyForm.test.tsx +++ b/source/frontend/src/features/mapSideBar/property/tabs/propertyResearch/update/UpdatePropertyForm.test.tsx @@ -47,6 +47,7 @@ const testResearchFile: ApiGen_Concepts_ResearchFileProperty = { file: null, displayOrder: null, property: null, + location: null, fileId: 0, }; diff --git a/source/frontend/src/features/mapSideBar/research/add/AddResearchContainer.test.tsx b/source/frontend/src/features/mapSideBar/research/add/AddResearchContainer.test.tsx index c2fa74c739..4498aaed3d 100644 --- a/source/frontend/src/features/mapSideBar/research/add/AddResearchContainer.test.tsx +++ b/source/frontend/src/features/mapSideBar/research/add/AddResearchContainer.test.tsx @@ -96,6 +96,7 @@ describe('AddResearchContainer component', () => { ...mapMachineBaseMock, selectedFeatureDataset: { location: { lat: 0, lng: 0 }, + fileLocation: null, pimsFeature: null, parcelFeature: selectedFeature, regionFeature: null, diff --git a/source/frontend/src/features/mapSideBar/shared/update/properties/UpdateProperties.test.tsx b/source/frontend/src/features/mapSideBar/shared/update/properties/UpdateProperties.test.tsx index bd691b88c8..fdf8bf2c6f 100644 --- a/source/frontend/src/features/mapSideBar/shared/update/properties/UpdateProperties.test.tsx +++ b/source/frontend/src/features/mapSideBar/shared/update/properties/UpdateProperties.test.tsx @@ -123,6 +123,7 @@ describe('UpdateProperties component', () => { displayOrder: null, fileId: 1, propertyName: null, + location: null, file: null, }, ], diff --git a/source/frontend/src/features/research/list/ResearchListView.test.tsx b/source/frontend/src/features/research/list/ResearchListView.test.tsx index 22dd0e96ae..ab7d615f46 100644 --- a/source/frontend/src/features/research/list/ResearchListView.test.tsx +++ b/source/frontend/src/features/research/list/ResearchListView.test.tsx @@ -571,6 +571,7 @@ const mockResearchListViewResponse: ApiGen_Concepts_ResearchFile[] = [ propertyName: null, purposeTypes: null, researchSummary: null, + location: null, file: null, }, { @@ -603,6 +604,7 @@ const mockResearchListViewResponse: ApiGen_Concepts_ResearchFile[] = [ propertyName: null, purposeTypes: null, researchSummary: null, + location: null, file: null, }, ], From d8caae7a32a8de699824ab5fc3b8726f8f9f74f8 Mon Sep 17 00:00:00 2001 From: Alejandro Sanchez Date: Mon, 1 Jul 2024 16:42:18 -0700 Subject: [PATCH 08/10] Bug fix --- source/backend/api/Services/AcquisitionFileService.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source/backend/api/Services/AcquisitionFileService.cs b/source/backend/api/Services/AcquisitionFileService.cs index 824c2f1890..c190a0a871 100644 --- a/source/backend/api/Services/AcquisitionFileService.cs +++ b/source/backend/api/Services/AcquisitionFileService.cs @@ -223,6 +223,12 @@ public PimsAcquisitionFile Add(PimsAcquisitionFile acquisitionFile, IEnumerable< PopulateAcquisitionChecklist(acquisitionFile); + // Update file specific marker locations + foreach (var incomingAcquisitionProperty in acquisitionFile.PimsPropertyAcquisitionFiles) + { + _propertyService.PopulateNewFileProperty(incomingAcquisitionProperty); + } + acquisitionFile.AcquisitionFileStatusTypeCode = AcquisitionStatusTypes.ACTIVE.ToString(); var newAcqFile = _acqFileRepository.Add(acquisitionFile); _acqFileRepository.CommitTransaction(); From 7bdcb2545c5000e6293e677acd253084213ae910 Mon Sep 17 00:00:00 2001 From: Alejandro Sanchez Date: Mon, 1 Jul 2024 16:45:39 -0700 Subject: [PATCH 09/10] Display file marker location when opening sidebar --- .../mapSideBar/context/sidebarContext.tsx | 5 +++-- .../src/hooks/useDraftMarkerSynchronizer.ts | 5 ++--- source/frontend/src/utils/mapPropertyUtils.ts | 15 +++++++++++++++ 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/source/frontend/src/features/mapSideBar/context/sidebarContext.tsx b/source/frontend/src/features/mapSideBar/context/sidebarContext.tsx index 71bd143b06..58bd43b52f 100644 --- a/source/frontend/src/features/mapSideBar/context/sidebarContext.tsx +++ b/source/frontend/src/features/mapSideBar/context/sidebarContext.tsx @@ -7,7 +7,7 @@ import { Api_LastUpdatedBy } from '@/models/api/File'; import { ApiGen_Concepts_File } from '@/models/api/generated/ApiGen_Concepts_File'; import { ApiGen_Concepts_Project } from '@/models/api/generated/ApiGen_Concepts_Project'; import { exists } from '@/utils'; -import { getLatLng } from '@/utils/mapPropertyUtils'; +import { getLatLng, locationFromFileProperty } from '@/utils/mapPropertyUtils'; export interface TypedFile extends ApiGen_Concepts_File { fileType: FileTypes; @@ -120,7 +120,8 @@ export const SideBarContextProvider = (props: { const resetFilePropertyLocations = useCallback(() => { if (exists(fileProperties)) { const propertyLocations = fileProperties - .map(x => getLatLng(x.property?.location)) + .map(x => locationFromFileProperty(x)) + .map(y => getLatLng(y)) .filter(exists); setFilePropertyLocations && setFilePropertyLocations(propertyLocations); diff --git a/source/frontend/src/hooks/useDraftMarkerSynchronizer.ts b/source/frontend/src/hooks/useDraftMarkerSynchronizer.ts index afe69260a5..1dd618f11c 100644 --- a/source/frontend/src/hooks/useDraftMarkerSynchronizer.ts +++ b/source/frontend/src/hooks/useDraftMarkerSynchronizer.ts @@ -6,6 +6,7 @@ import { useMapStateMachine } from '@/components/common/mapFSM/MapStateMachineCo import { IMapProperty } from '@/components/propertySelector/models'; import useDeepCompareEffect from '@/hooks/util/useDeepCompareEffect'; import useIsMounted from '@/hooks/util/useIsMounted'; +import { latLngFromMapProperty } from '@/utils'; /** * Get a list of file property markers from the current form values. @@ -13,9 +14,7 @@ import useIsMounted from '@/hooks/util/useIsMounted'; * @param modifiedProperties the current form values to extract lat/lngs from. */ const getFilePropertyLocations = (modifiedProperties: IMapProperty[]): LatLngLiteral[] => { - return modifiedProperties.map((property: IMapProperty) => { - return { lat: Number(property?.latitude ?? 0), lng: Number(property?.longitude ?? 0) }; - }); + return modifiedProperties.map((property: IMapProperty) => latLngFromMapProperty(property)); }; /** diff --git a/source/frontend/src/utils/mapPropertyUtils.ts b/source/frontend/src/utils/mapPropertyUtils.ts index 9aac704091..e7e1833bdd 100644 --- a/source/frontend/src/utils/mapPropertyUtils.ts +++ b/source/frontend/src/utils/mapPropertyUtils.ts @@ -266,3 +266,18 @@ export function pinFromFeatureSet(featureset: LocationFeatureDataset): string | null ); } + +export function locationFromFileProperty( + fileProperty: ApiGen_Concepts_FileProperty | undefined | null, +): ApiGen_Concepts_Geometry | null { + return fileProperty?.location ?? fileProperty?.property?.location ?? null; +} + +export function latLngFromMapProperty( + mapProperty: IMapProperty | undefined | null, +): LatLngLiteral | null { + return { + lat: Number(mapProperty?.fileLocation?.lat ?? mapProperty?.latitude ?? 0), + lng: Number(mapProperty?.fileLocation?.lng ?? mapProperty?.longitude ?? 0), + }; +} From a44409e18cc4c07fddc9402269d5ea4ef7d943a3 Mon Sep 17 00:00:00 2001 From: Alejandro Sanchez Date: Tue, 2 Jul 2024 15:32:00 -0700 Subject: [PATCH 10/10] Test updates --- .../Services/AcquisitionFileServiceTest.cs | 1 + .../src/utils/mapPropertyUtils.test.tsx | 49 +++++++++++-------- 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/source/backend/tests/unit/api/Services/AcquisitionFileServiceTest.cs b/source/backend/tests/unit/api/Services/AcquisitionFileServiceTest.cs index 3242bbfcaa..489b7c278e 100644 --- a/source/backend/tests/unit/api/Services/AcquisitionFileServiceTest.cs +++ b/source/backend/tests/unit/api/Services/AcquisitionFileServiceTest.cs @@ -1344,6 +1344,7 @@ public void UpdateProperties_MatchProperties_NewProperty_Success() RegionCode = 1, } ); + propertyService.Setup(x => x.PopulateNewFileProperty(It.IsAny())).Returns(x => x); var userRepository = this._helper.GetService>(); userRepository.Setup(x => x.GetUserInfoByKeycloakUserId(It.IsAny())).Returns(EntityHelper.CreateUser(1, Guid.NewGuid(), "Test", regionCode: 1)); diff --git a/source/frontend/src/utils/mapPropertyUtils.test.tsx b/source/frontend/src/utils/mapPropertyUtils.test.tsx index f0ff513d25..fa67062d77 100644 --- a/source/frontend/src/utils/mapPropertyUtils.test.tsx +++ b/source/frontend/src/utils/mapPropertyUtils.test.tsx @@ -31,6 +31,7 @@ const expectedMapProperty = { landArea: 647.4646, latitude: 48.432802005, longitude: -123.310041775, + legalDescription: undefined, name: undefined, pid: '000002500', pin: undefined, @@ -39,6 +40,10 @@ const expectedMapProperty = { coordinates: [[[-123.31014591, 48.43274258]]], type: 'Polygon', }, + fileLocation: { + lat: 48.432802005, + lng: -123.310041775, + }, propertyId: undefined, region: 1, regionName: 'South Coast', @@ -90,7 +95,7 @@ describe('mapPropertyUtils', () => { [{ address: '' }, { label: NameSourceType.NONE, value: '' }], [{ address: '1234 fake st' }, { label: NameSourceType.ADDRESS, value: '1234 fake st' }], ])( - 'getPropertyName test with source %p expecting %p', + 'getPropertyName test with source %o expecting %o', (mapProperty: IMapProperty, expectedName: PropertyName) => { const actualName = getPropertyName(mapProperty); expect(actualName.label).toEqual(expectedName.label); @@ -98,24 +103,20 @@ describe('mapPropertyUtils', () => { }, ); - it('getPrettyLatLng, empty', () => { - const prettyLatLng = getPrettyLatLng(undefined); - expect(prettyLatLng).toEqual(''); - }); - - it('getPrettyLatLng, valued', () => { - const prettyLatLng = getPrettyLatLng({ coordinate: { x: 1, y: 2 } }); - expect(prettyLatLng).toEqual('1.000000, 2.000000'); - }); - - it('getLatLng, empty', () => { - const latLng = getLatLng(undefined); - expect(latLng).toEqual(null); + it.each([ + ['empty', undefined, ''], + ['valued', { coordinate: { x: 1, y: 2 } }, '1.000000, 2.000000'], + ])('getPrettyLatLng - %s', (_, value, expected) => { + const prettyLatLng = getPrettyLatLng(value); + expect(prettyLatLng).toEqual(expected); }); - it('getLatLng, valued', () => { - const latLng = getLatLng({ coordinate: { x: 1, y: 2 } }); - expect(latLng).toEqual({ lat: 2, lng: 1 }); + it.each([ + ['empty', undefined, null], + ['valued', { coordinate: { x: 1, y: 2 } }, { lat: 2, lng: 1 }], + ])('getLatLng - %s', (_, value, expected) => { + const latLng = getLatLng(value); + expect(latLng).toEqual(expected); }); it.each([ @@ -152,7 +153,7 @@ describe('mapPropertyUtils', () => { { ...getEmptyFileProperty(), property: { ...getEmptyProperty(), pid: 1 } }, ], ])( - 'getFilePropertyName test with ignore name flag %p expecting %p source %p', + 'getFilePropertyName test with ignore name flag %o expecting %s source %o', (skipName: boolean, expectedName: PropertyName, mapProperty?: ApiGen_Concepts_FileProperty) => { const fileName = getFilePropertyName(mapProperty, skipName); expect(fileName.label).toEqual(expectedName.label); @@ -183,6 +184,10 @@ describe('mapPropertyUtils', () => { propertyId: undefined, region: undefined, regionName: undefined, + fileLocation: { + lat: 48.76613749999999, + lng: -123.46163749999998, + }, }, ], ], @@ -207,11 +212,15 @@ describe('mapPropertyUtils', () => { propertyId: undefined, region: undefined, regionName: undefined, + fileLocation: { + lat: 48.76613749999999, + lng: -123.46163749999998, + }, }, ], ], ])( - 'featuresToIdentifiedMapProperty test with feature values %p and address %p and expected map properties %p', + 'featuresToIdentifiedMapProperty test with feature values %o and address %o and expected map properties %o', ( values: FeatureCollection | undefined, address?: string, @@ -242,7 +251,7 @@ describe('mapPropertyUtils', () => { { ...expectedMapProperty, address: 'address' }, ], ])( - 'featuresetToMapProperty test with feature set %p address %p expectedPropertyFile %p', + 'featuresetToMapProperty test with feature set %o address %o expectedPropertyFile %o', ( featureSet: LocationFeatureDataset, address: string = 'unknown',