Skip to content

Commit

Permalink
Advanced Map - added pin or draw, migration added for adding geoJSON,…
Browse files Browse the repository at this point in the history
… model & types updated, externalAPIService updated
  • Loading branch information
sanjaytkbabu committed Nov 28, 2024
1 parent d4aa66c commit caedfcf
Show file tree
Hide file tree
Showing 19 changed files with 302 additions and 8 deletions.
1 change: 1 addition & 0 deletions .github/environments/values.dev.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ config:
FRONTEND_GEOCODER_APIPATH: https://geocoder.api.gov.bc.ca
FRONTEND_OIDC_AUTHORITY: https://dev.loginproxy.gov.bc.ca/auth/realms/standard
FRONTEND_OIDC_CLIENTID: nr-permit-connect-navigator-service-5188
FRONTEND_OPENMAPS_APIPATH: https://openmaps.gov.bc.ca/geo/pub/wfs?SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&outputFormat=json&typeName=WHSE_CADASTRE.PMBC_PARCEL_FABRIC_POLY_SVW&CQL_FILTER=INTERSECTS(SHAPE, POLYGON ((query)))
FRONTEND_OPENSTREETMAP_APIPATH: https://tile.openstreetmap.org
FRONTEND_ORGBOOK_APIPATH: https://orgbook.gov.bc.ca/api/v4
SERVER_APIPATH: /api/v1
Expand Down
1 change: 1 addition & 0 deletions .github/environments/values.prod.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ config:
FRONTEND_GEOCODER_APIPATH: https://geocoder.api.gov.bc.ca
FRONTEND_OIDC_AUTHORITY: https://loginproxy.gov.bc.ca/auth/realms/standard
FRONTEND_OIDC_CLIENTID: nr-permit-connect-navigator-service-5188
FRONTEND_OPENMAPS_APIPATH: https://openmaps.gov.bc.ca/geo/pub/wfs?SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&outputFormat=json&typeName=WHSE_CADASTRE.PMBC_PARCEL_FABRIC_POLY_SVW&CQL_FILTER=INTERSECTS(SHAPE, POLYGON ((query)))
FRONTEND_OPENSTREETMAP_APIPATH: https://tile.openstreetmap.org
FRONTEND_ORGBOOK_APIPATH: https://orgbook.gov.bc.ca/api/v4
SERVER_APIPATH: /api/v1
Expand Down
1 change: 1 addition & 0 deletions .github/environments/values.test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ config:
FRONTEND_GEOCODER_APIPATH: https://geocoder.api.gov.bc.ca
FRONTEND_OIDC_AUTHORITY: https://test.loginproxy.gov.bc.ca/auth/realms/standard
FRONTEND_OIDC_CLIENTID: nr-permit-connect-navigator-service-5188
FRONTEND_OPENMAPS_APIPATH: https://openmaps.gov.bc.ca/geo/pub/wfs?SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&outputFormat=json&typeName=WHSE_CADASTRE.PMBC_PARCEL_FABRIC_POLY_SVW&CQL_FILTER=INTERSECTS(SHAPE, POLYGON ((query)))
FRONTEND_OPENSTREETMAP_APIPATH: https://tile.openstreetmap.org
FRONTEND_ORGBOOK_APIPATH: https://orgbook.gov.bc.ca/api/v4
SERVER_APIPATH: /api/v1
Expand Down
3 changes: 3 additions & 0 deletions app/config/custom-environment-variables.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
"authority": "FRONTEND_OIDC_AUTHORITY",
"clientId": "FRONTEND_OIDC_CLIENTID"
},
"openMaps": {
"apiPath": "FRONTEND_OPENMAPS_APIPATH"
},
"openStreetMap": {
"apiPath": "FRONTEND_OPENSTREETMAP_APIPATH"
},
Expand Down
1 change: 1 addition & 0 deletions app/src/controllers/submission.ts
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ const controller = {
naturalDisaster: data.location.naturalDisaster,
projectLocation: data.location.projectLocation,
projectLocationDescription: data.location.projectLocationDescription,
geoJSON: data.location.geoJSON,
locationPIDs: data.location.ltsaPIDLookup,
latitude: data.location.latitude,
longitude: data.location.longitude,
Expand Down
19 changes: 19 additions & 0 deletions app/src/db/migrations/20241127000000_016-advanced-map.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/* eslint-disable max-len */
import type { Knex } from 'knex';

export async function up(knex: Knex): Promise<void> {
return Promise.resolve().then(() =>
knex.schema.alterTable('submission', function (table) {
table.json('geo_json');
})
);
}

export async function down(knex: Knex): Promise<void> {
return Promise.resolve() // Drop public schema tables
.then(() =>
knex.schema.alterTable('submission', function (table) {
table.dropColumn('geo_json');
})
);
}
3 changes: 3 additions & 0 deletions app/src/db/models/submission.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ export default {
consent_to_feedback: input.consentToFeedback,
location_pids: input.locationPIDs,
company_name_registered: input.companyNameRegistered,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
geo_json: input.geoJSON as any,
single_family_units: input.singleFamilyUnits,
has_rental_units: input.hasRentalUnits,
street_address: input.streetAddress,
Expand Down Expand Up @@ -110,6 +112,7 @@ export default {
projectName: input.project_name,
projectDescription: input.project_description,
companyNameRegistered: input.company_name_registered,
geoJSON: input.geo_json,
singleFamilyUnits: input.single_family_units,
hasRentalUnits: input.has_rental_units,
streetAddress: input.street_address,
Expand Down
1 change: 1 addition & 0 deletions app/src/db/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,7 @@ model submission {
housing_coop_description String?
submission_type String?
consent_to_feedback Boolean @default(false)
geo_json Json? @db.Json
activity activity @relation(fields: [activity_id], references: [activity_id], onDelete: Cascade, map: "submission_activity_id_foreign")
user user? @relation(fields: [assigned_user_id], references: [user_id], onDelete: Cascade, map: "submission_assigned_user_id_foreign")
Expand Down
6 changes: 4 additions & 2 deletions app/src/services/submission.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ const service = {
*/
createSubmission: async (data: Partial<Submission>) => {
const response = await prisma.submission.create({
//@ts-expect-error please help
data: { ...submission.toPrismaModel(data as Submission), created_at: data.createdAt, created_by: data.createdBy },
include: {
activity: {
Expand All @@ -48,7 +49,7 @@ const service = {
}
}
});

//@ts-expect-error please help
return submission.fromPrismaModelWithContact(response);
},

Expand Down Expand Up @@ -352,6 +353,7 @@ const service = {
updateSubmission: async (data: Submission) => {
try {
const result = await prisma.submission.update({
//@ts-expect-error please help
data: { ...submission.toPrismaModel(data), updated_at: data.updatedAt, updated_by: data.updatedBy },
where: {
submission_id: data.submissionId
Expand All @@ -368,7 +370,7 @@ const service = {
}
}
});

//@ts-expect-error please help
return submission.fromPrismaModelWithContact(result);
} catch (e: unknown) {
throw e;
Expand Down
2 changes: 2 additions & 0 deletions app/src/types/Submission.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ export type Submission = {
locationPIDs: string | null;
companyNameRegistered: string | null;
consentToFeedback: boolean;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
geoJSON: any;
projectName: string | null;
projectDescription: string | null;
singleFamilyUnits: string | null;
Expand Down
1 change: 1 addition & 0 deletions app/src/types/SubmissionIntake.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export type SubmissionIntake = {
naturalDisaster?: string;
projectLocation?: string;
projectLocationDescription?: string;
geoJSON?: JSON;
ltsaPIDLookup?: string;
latitude?: number | null;
longitude?: number | null;
Expand Down
1 change: 1 addition & 0 deletions charts/pcns/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ config:
FRONTEND_GEOCODER_APIPATH: ~
FRONTEND_OIDC_AUTHORITY: ~
FRONTEND_OIDC_CLIENTID: ~
FRONTEND_OPENMAPS_APIPATH: ~
FRONTEND_OPENSTREETMAP_APIPATH: ~
FRONTEND_ORGBOOK_APIPATH: ~

Expand Down
108 changes: 105 additions & 3 deletions frontend/src/components/housing/maps/Map.vue
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
<script setup lang="ts">
import * as L from 'leaflet';
import type { GeoJSON } from 'geojson';
import 'leaflet/dist/leaflet.css';
import '@geoman-io/leaflet-geoman-free';
import '@geoman-io/leaflet-geoman-free/dist/leaflet-geoman.css';
import { onMounted, onUpdated, watch } from 'vue';
import { onMounted, onUpdated, ref, watch } from 'vue';
import markerIcon from 'leaflet/dist/images/marker-icon.png';
L.Marker.prototype.setIcon(
L.icon({
iconUrl: markerIcon
})
);
import { useToast } from '@/lib/primevue';
import { externalApiService } from '@/services';
import {
BC_BOUNDARIES_LOWER,
BC_BOUNDARIES_UPPER,
Expand All @@ -14,20 +22,33 @@ import {
OSM_URL_TEMPLATE
} from '@/utils/constants/mapping';
import type { Ref } from 'vue';
// Props
const {
disabled = false,
latitude = undefined,
longitude = undefined
longitude = undefined,
pinOrDraw = false
} = defineProps<{
disabled?: boolean;
latitude?: number;
longitude?: number;
pinOrDraw?: boolean;
}>();
// Constants
const POINT = 'Point';
// Actions
let marker: L.Marker;
let map: L.Map;
const parcelData: Ref<Array<unknown>> = ref([]);
const geoJSON: Ref<GeoJSON | undefined> = ref(undefined);
const toast = useToast();
// Emits
const emit = defineEmits(['map:polygonUpdated', 'map:pinUpdated']);
async function initMap() {
const osm = L.tileLayer(OSM_URL_TEMPLATE, OSM_TILE_LAYER_OPTIONS);
Expand All @@ -43,6 +64,87 @@ async function initMap() {
map.on('drag', function () {
map.panInsideBounds(bcBounds, { animate: false });
});
if (pinOrDraw) {
map.on('pm:create', async (e) => {
try {
const geo = e.layer as L.GeoJSON;
//@ts-ignore
if (geo.toGeoJSON().geometry.type === POINT) {
//@ts-ignore
let latitude = geo.toGeoJSON().geometry.coordinates[1];
//@ts-ignore
let longitude = geo.toGeoJSON().geometry.coordinates[0];
getNearestOccupant(longitude, latitude);
} else {
// Show parcel data using WFS api
//@ts-ignore
showPMBCParcelData(geo.getLatLngs()[0]);
}
//@ts-ignore
geoJSON.value = geo.toGeoJSON();
// Zoom in
if (geo.getBounds) map.fitBounds(geo.getBounds());
//@ts-ignore
else map.flyTo(geo.getLatLng(), 17);
} catch (e: any) {
toast.error('Error', e.message);
}
});
// On feature remove
map.on('pm:remove', async (e) => {
try {
const geo = e.layer as L.GeoJSON;

Check warning on line 99 in frontend/src/components/housing/maps/Map.vue

View workflow job for this annotation

GitHub Actions / Unit Tests (Frontend) (16.x)

'geo' is assigned a value but never used

Check warning on line 99 in frontend/src/components/housing/maps/Map.vue

View workflow job for this annotation

GitHub Actions / Unit Tests (Frontend) (18.x)

'geo' is assigned a value but never used

Check warning on line 99 in frontend/src/components/housing/maps/Map.vue

View workflow job for this annotation

GitHub Actions / Unit Tests (Frontend) (20.x)

'geo' is assigned a value but never used

Check warning on line 99 in frontend/src/components/housing/maps/Map.vue

View workflow job for this annotation

GitHub Actions / Unit Tests (Frontend) (16.x)

'geo' is assigned a value but never used

Check warning on line 99 in frontend/src/components/housing/maps/Map.vue

View workflow job for this annotation

GitHub Actions / Unit Tests (Frontend) (18.x)

'geo' is assigned a value but never used

Check warning on line 99 in frontend/src/components/housing/maps/Map.vue

View workflow job for this annotation

GitHub Actions / Unit Tests (Frontend) (20.x)

'geo' is assigned a value but never used

Check warning on line 99 in frontend/src/components/housing/maps/Map.vue

View workflow job for this annotation

GitHub Actions / Unit Tests (Frontend) (16.x)

'geo' is assigned a value but never used

Check warning on line 99 in frontend/src/components/housing/maps/Map.vue

View workflow job for this annotation

GitHub Actions / Unit Tests (Frontend) (18.x)

'geo' is assigned a value but never used

Check warning on line 99 in frontend/src/components/housing/maps/Map.vue

View workflow job for this annotation

GitHub Actions / Unit Tests (Frontend) (20.x)

'geo' is assigned a value but never used
} catch (e: any) {
// toast.error('Error', e.message);
}
});
initControls();
}
}
// show parcel data from Geocoder
async function showPMBCParcelData(polygon: Array<any>) {
await externalApiService.getParcelDataFromPMBC(polygon).then((data: any) => {
parcelData.value = data.features.map((f: any) => f.properties);
// get comma separated PIDs
const PIDs = parcelData.value.map((p: any) => p.PID_FORMATTED).join(',');
emit('map:polygonUpdated', { PID: PIDs, geoJSON: geoJSON.value });
});
}
// show parcel data from Geocoder
async function getNearestOccupant(longitude: string, latitude: string) {
const result = await externalApiService.getNearestOccupant(longitude, latitude);
const address = result.data.properties.occupantAliasAddress;
if (!address || address.length == 0) {
toast.warn('No address found');
}
emit('map:pinUpdated', {
longitude: longitude,
latitude: latitude,
address: address
});
}
function initControls() {
map.pm.addControls({
position: 'topleft',
// Create
drawCircleMarker: false,
drawCircle: false,
drawText: false,
drawPolyline: false,
// Edit
cutPolygon: false,
dragMode: false,
editMode: false,
rotateMode: false
});
}
function disableInteraction() {
Expand Down
Loading

0 comments on commit caedfcf

Please sign in to comment.