From 67d2342f27ba9eb61412afaf54f8c218e8f1126b Mon Sep 17 00:00:00 2001 From: Mike Sears Date: Thu, 2 Nov 2023 21:04:59 -0700 Subject: [PATCH 1/3] enabled search on map view --- .../allegation_complaint.service.ts | 7 +++++++ .../hwcr_complaint/hwcr_complaint.service.ts | 7 +++++++ .../containers/complaints/complaint-map.tsx | 19 +++++++++++++------ .../containers/complaints/complaints.tsx | 2 +- .../app/store/reducers/complaint-locations.ts | 2 ++ 5 files changed, 30 insertions(+), 7 deletions(-) diff --git a/backend/src/v1/allegation_complaint/allegation_complaint.service.ts b/backend/src/v1/allegation_complaint/allegation_complaint.service.ts index ad396521d..24d886bca 100644 --- a/backend/src/v1/allegation_complaint/allegation_complaint.service.ts +++ b/backend/src/v1/allegation_complaint/allegation_complaint.service.ts @@ -175,9 +175,16 @@ export class AllegationComplaintService { searchMap = async ( model: SearchPayload ): Promise> => { + const { query } = model; + //-- build generic wildlife query let builder = this._getAllegationQuery(); + //-- apply search + if (query) { + builder = this._applySearch(builder, query); + } + //-- apply filters builder = this._applyAllegationQueryFilters( builder, diff --git a/backend/src/v1/hwcr_complaint/hwcr_complaint.service.ts b/backend/src/v1/hwcr_complaint/hwcr_complaint.service.ts index 80c417fd8..50f2a0183 100644 --- a/backend/src/v1/hwcr_complaint/hwcr_complaint.service.ts +++ b/backend/src/v1/hwcr_complaint/hwcr_complaint.service.ts @@ -153,9 +153,16 @@ export class HwcrComplaintService { }; searchMap = async (model: SearchPayload): Promise => { + const { query } = model; + //-- build generic wildlife query let builder = this._getWildlifeQuery(); + //-- apply search + if (query) { + builder = this._applySearch(builder, query); + } + //-- apply filters builder = this._applyWildlifeQueryFilters(builder, model as SearchPayload); diff --git a/frontend/src/app/components/containers/complaints/complaint-map.tsx b/frontend/src/app/components/containers/complaints/complaint-map.tsx index c2307752a..2bccb5cd8 100644 --- a/frontend/src/app/components/containers/complaints/complaint-map.tsx +++ b/frontend/src/app/components/containers/complaints/complaint-map.tsx @@ -14,9 +14,10 @@ import { type Props = { type: string; + searchQuery: string }; -export const ComplaintMap: FC = ({ type }) => { +export const ComplaintMap: FC = ({ type, searchQuery }) => { const dispatch = useAppDispatch(); const coordinatesArray = useAppSelector(selectComplaintLocations(type)); @@ -28,6 +29,17 @@ export const ComplaintMap: FC = ({ type }) => { const [sortKey, setSortKey] = useState("incident_reported_utc_timestmp"); const [sortDirection, setSortDirection] = useState(SORT_TYPES.DESC); + useEffect(() => { + let payload = generateComplaintRequestPayload(type, filters); + + if (searchQuery) { + payload = { ...payload, query: searchQuery }; + } + + dispatch(getComplaintsOnMap(type, payload)); + }, [filters, searchQuery]); + + const generateComplaintRequestPayload = ( complaintType: string, filters: ComplaintFilters, @@ -73,11 +85,6 @@ export const ComplaintMap: FC = ({ type }) => { } }; - useEffect(() => { - const payload = generateComplaintRequestPayload(type, filters); - dispatch(getComplaintsOnMap(type, payload)); - }, [filters]); - useEffect(() => { //-- when the component unmounts clear the complaint from redux return () => { diff --git a/frontend/src/app/components/containers/complaints/complaints.tsx b/frontend/src/app/components/containers/complaints/complaints.tsx index b5184173f..c9aceddc1 100644 --- a/frontend/src/app/components/containers/complaints/complaints.tsx +++ b/frontend/src/app/components/containers/complaints/complaints.tsx @@ -190,7 +190,7 @@ export const Complaints: FC = ({ defaultComplaintType }) => { {viewType === "list" ? ( ) : ( - + )} diff --git a/frontend/src/app/store/reducers/complaint-locations.ts b/frontend/src/app/store/reducers/complaint-locations.ts index 5a9aa6da2..619515a45 100644 --- a/frontend/src/app/store/reducers/complaint-locations.ts +++ b/frontend/src/app/store/reducers/complaint-locations.ts @@ -75,6 +75,7 @@ export const getComplaintsOnMap = endDateFilter, violationFilter, complaintStatusFilter, + query } = payload; try { dispatch(toggleLoading(true)); @@ -102,6 +103,7 @@ export const getComplaintsOnMap = incidentReportedEnd: endDateFilter, violationCode: violationFilter?.value, status: complaintStatusFilter?.value, + query }, ); const response = await get< From 3f0d4d09d380bd9f5bcdf88403f8174cfb28d716 Mon Sep 17 00:00:00 2001 From: Mike Sears Date: Fri, 3 Nov 2023 16:14:13 -0700 Subject: [PATCH 2/3] cypress tests created for single and multiple complaint map search --- .../cypress/e2e/complaint-search.v2.cy.ts | 195 ++++++++++++------ .../app/components/common/search-input.tsx | 17 +- .../complaints/complaint-filter-bar.tsx | 2 +- .../containers/complaints/complaint-map.tsx | 95 ++++----- .../leaflet-map-with-multiple-points.tsx | 1 + 5 files changed, 194 insertions(+), 116 deletions(-) diff --git a/frontend/cypress/e2e/complaint-search.v2.cy.ts b/frontend/cypress/e2e/complaint-search.v2.cy.ts index 1f6621f26..10bef7b03 100644 --- a/frontend/cypress/e2e/complaint-search.v2.cy.ts +++ b/frontend/cypress/e2e/complaint-search.v2.cy.ts @@ -49,98 +49,159 @@ describe("Complaint Search Functionality", () => { }); it("Can search Allegations for 'RAPP'", () => { - cy.visit("/"); - cy.waitForSpinner(); + cy.visit("/"); + cy.waitForSpinner(); - //-- load the Enforcement conflicts - cy.get(complaintTypes[1]).click({ force: true }); + //-- load the Enforcement conflicts + cy.get(complaintTypes[1]).click({ force: true }); - //-- verify correct tab - cy.get("#ers-tab").should("contain.text", "Enforcement"); + //-- verify correct tab + cy.get("#ers-tab").should("contain.text", "Enforcement"); - //-- remove filters - cy.get("#comp-status-filter").click({ force: true }); - cy.get("#comp-status-filter").should("not.exist"); + //-- remove filters + cy.get("#comp-status-filter").click({ force: true }); + cy.get("#comp-status-filter").should("not.exist"); - //-- there should be 33 complaints - cy.get("#complaint-list tbody").find("tr").should("have.length", 33); + //-- there should be 33 complaints + cy.get("#complaint-list tbody").find("tr").should("have.length", 33); - //-- search for RAPP and verify there's siz complaints - cy.get("#complaint-search").click({ force: true }); - cy.get("#complaint-search").clear().type("RAPP{enter}"); //-- {enter} will perform an enter keypress + //-- search for RAPP and verify there's siz complaints + cy.get("#complaint-search").click({ force: true }); + cy.get("#complaint-search").clear().type("RAPP{enter}"); //-- {enter} will perform an enter keypress - //-- verify one complaint, and verify complaint-id - cy.get("#complaint-list tbody").find("tr").should("have.length", 6); - }); + //-- verify one complaint, and verify complaint-id + cy.get("#complaint-list tbody").find("tr").should("have.length", 6); + }); - it("Search should clear when switching tabs", () => { - cy.visit("/"); - cy.waitForSpinner(); + it("Search should clear when switching tabs", () => { + cy.visit("/"); + cy.waitForSpinner(); - //-- load the Enforcement conflicts - cy.get(complaintTypes[1]).click({ force: true }); + //-- load the Enforcement conflicts + cy.get(complaintTypes[1]).click({ force: true }); - //-- verify correct tab - cy.get("#ers-tab").should("contain.text", "Enforcement"); + //-- verify correct tab + cy.get("#ers-tab").should("contain.text", "Enforcement"); - //-- remove filters - cy.get("#comp-status-filter").click({ force: true }); - cy.get("#comp-status-filter").should("not.exist"); + //-- remove filters + cy.get("#comp-status-filter").click({ force: true }); + cy.get("#comp-status-filter").should("not.exist"); - //-- there should be 33 complaints - cy.get("#complaint-list tbody").find("tr").should("have.length", 33); + //-- there should be 33 complaints + cy.get("#complaint-list tbody").find("tr").should("have.length", 33); - //-- search for RAPP and verify there's siz complaints - cy.get("#complaint-search").click({ force: true }); - cy.get("#complaint-search").clear().type("RAPP{enter}"); //-- {enter} will perform an enter keypress + //-- search for RAPP and verify there's siz complaints + cy.get("#complaint-search").click({ force: true }); + cy.get("#complaint-search").clear().type("RAPP{enter}"); //-- {enter} will perform an enter keypress - //-- verify one complaint, and verify complaint-id - cy.get("#complaint-list tbody").find("tr").should("have.length", 6); + //-- verify one complaint, and verify complaint-id + cy.get("#complaint-list tbody").find("tr").should("have.length", 6); - //-- switch tabs - cy.get(complaintTypes[0]).click({ force: true }); + //-- switch tabs + cy.get(complaintTypes[0]).click({ force: true }); - //-- verify empty search - cy.get("#complaint-search").should('have.value', ''); - }); + //-- verify empty search + cy.get("#complaint-search").should("have.value", ""); + }); - it("Can't search Wildlife complaints for 'Zebra'", () => { - cy.visit("/"); - cy.waitForSpinner(); + it("Can't search Wildlife complaints for 'Zebra'", () => { + cy.visit("/"); + cy.waitForSpinner(); - //-- load the human wildlife conflicts - cy.get(complaintTypes[0]).click({ force: true }); + //-- load the human wildlife conflicts + cy.get(complaintTypes[0]).click({ force: true }); - //-- verify correct tab - cy.get("#hwcr-tab").should("contain.text", "Human Wildlife Conflicts"); + //-- verify correct tab + cy.get("#hwcr-tab").should("contain.text", "Human Wildlife Conflicts"); - //-- remove filters - cy.get("#comp-status-filter").click({ force: true }); - cy.get("#comp-zone-filter").click({ force: true }); + //-- remove filters + cy.get("#comp-status-filter").click({ force: true }); + cy.get("#comp-zone-filter").click({ force: true }); - cy.get("#comp-status-filter").should("not.exist"); - cy.get("#comp-zone-filter").should("not.exist"); + cy.get("#comp-status-filter").should("not.exist"); + cy.get("#comp-zone-filter").should("not.exist"); - //-- open the filter tab - cy.get("#complaint-filter-image-id").click({ force: true }); + //-- open the filter tab + cy.get("#complaint-filter-image-id").click({ force: true }); - //-- select 70 mile house community - cy.selectItemById("community-select-id", "70 Mile House"); - - cy.get("#comp-community-filter").should("exist"); + //-- select 70 mile house community + cy.selectItemById("community-select-id", "70 Mile House"); - //-- close the filter - cy.get("#complaint-filter-image-id").click({ force: true }); + cy.get("#comp-community-filter").should("exist"); - //-- there should be 3 complaints - // cy.get("#complaint-list tbody").find("tr").should("have.length", 3); + //-- close the filter + cy.get("#complaint-filter-image-id").click({ force: true }); - //-- search for sibling and verify there's one complaint - cy.get("#complaint-search").click({ force: true }); - cy.get("#complaint-search").clear().type("Zebra{enter}"); //-- {enter} will perform an enter keypress + //-- search for sibling and verify there's one complaint + cy.get("#complaint-search").click({ force: true }); + cy.get("#complaint-search").clear().type("Zebra{enter}"); //-- {enter} will perform an enter keypress - //-- verify no complaints - cy.get("#complaint-list tbody").find("tr").should("have.length", 0); - }); + //-- verify no complaints + cy.get("#complaint-list tbody").find("tr").should("have.length", 0); + }); + + it("Can search wildlife map complaints by complaint-id: 23-031562", () => { + cy.visit("/"); + cy.waitForSpinner(); + + //-- load the human wildlife conflicts + cy.get(complaintTypes[0]).click({ force: true }); + + //-- verify correct tab + cy.get("#hwcr-tab").should("contain.text", "Human Wildlife Conflicts"); + + //-- search for sibling and verify there's one complaint + cy.get("#complaint-search").click({ force: true }); + cy.get("#complaint-search").clear().type("23-031562{enter}"); //-- {enter} will perform an enter keypress + + //-- verify only one complaint + cy.get("#complaint-list tbody").find("tr").should("have.length", 1); + + cy.get("#map_toggle_id").click({ force: true }); + cy.verifyMapMarkerExists(true); + + cy.get("#multi-point-map") + .find(".leaflet-marker-icon") + .should(({ length }) => { + expect(length).to.eq(1); + }); + }); + + it("Can search multiple allegation map complaints: ", () => { + cy.visit("/"); + cy.waitForSpinner(); + + //-- load the human wildlife conflicts + cy.get(complaintTypes[1]).click({ force: true }); + + //-- verify correct tab + cy.get("#ers-tab").should("contain.text", "Enforcement"); //comp-zone-filter + //-- remove the zone filter + cy.get("#comp-zone-filter").click({ force: true }); + cy.get("#comp-zone-filter").should("not.exist"); + + //-- open the filter tab + cy.get("#complaint-filter-image-id").click({ force: true }); + + //-- select east kootenay zone + cy.selectItemById("zone-select-id", "East Kootenay"); + cy.get("#comp-zone-filter").should("exist"); + + cy.get("#complaint-filter-image-id").click({ force: true }); + + //-- search for fire and verify there's multiple complaints + cy.get("#complaint-search").click({ force: true }); + cy.get("#complaint-search").clear().type("fire{enter}"); //-- {enter} will perform an enter keypress + + cy.get("#map_toggle_id").click({ force: true }); + cy.verifyMapMarkerExists(true); + + cy.get("#multi-point-map") + .find("div.leaflet-marker-icon") + .should(({ length }) => { + console.log(length); + expect(length).to.eq(5); + }); + }); }); diff --git a/frontend/src/app/components/common/search-input.tsx b/frontend/src/app/components/common/search-input.tsx index 84203b039..d14c10690 100644 --- a/frontend/src/app/components/common/search-input.tsx +++ b/frontend/src/app/components/common/search-input.tsx @@ -5,15 +5,19 @@ import { getComplaints } from "../../store/reducers/complaints"; import { generateComplaintRequestPayload } from "../containers/complaints/complaint-list"; import { useAppDispatch } from "../../hooks/hooks"; import { SORT_TYPES } from "../../constants/sort-direction"; +import { getComplaintsOnMap } from "../../store/reducers/complaint-locations"; +import { generateMapComplaintRequestPayload } from "../containers/complaints/complaint-map"; type Props = { complaintType: string; + viewType: "map" | "list"; searchQuery: string | undefined; applySearchQuery: Function; }; const SearchInput: FC = ({ complaintType, + viewType, searchQuery, applySearchQuery, }) => { @@ -43,7 +47,18 @@ const SearchInput: FC = ({ payload = { ...payload, query: input }; - dispatch(getComplaints(complaintType, payload)); + if(viewType === "list"){ + dispatch(getComplaints(complaintType, payload)); + } + else { + let payload = generateMapComplaintRequestPayload(complaintType, filters, "", ""); + + if (searchQuery) { + payload = { ...payload, query: searchQuery }; + } + + dispatch(getComplaintsOnMap(complaintType, payload)); + } } }; diff --git a/frontend/src/app/components/containers/complaints/complaint-filter-bar.tsx b/frontend/src/app/components/containers/complaints/complaint-filter-bar.tsx index 0bde6e4cc..d904ffa16 100644 --- a/frontend/src/app/components/containers/complaints/complaint-filter-bar.tsx +++ b/frontend/src/app/components/containers/complaints/complaint-filter-bar.tsx @@ -163,7 +163,7 @@ export const ComplaintFilterBar: FC = ({ viewType, toggleViewType, compla )}
- +
diff --git a/frontend/src/app/components/containers/complaints/complaint-map.tsx b/frontend/src/app/components/containers/complaints/complaint-map.tsx index 2bccb5cd8..04bf70b74 100644 --- a/frontend/src/app/components/containers/complaints/complaint-map.tsx +++ b/frontend/src/app/components/containers/complaints/complaint-map.tsx @@ -17,6 +17,53 @@ type Props = { searchQuery: string }; +export const generateMapComplaintRequestPayload = ( + complaintType: string, + filters: ComplaintFilters, + sortKey: string, + sortDirection: string +): ComplaintRequestPayload => { + const { + region, + zone, + community, + officer, + startDate, + endDate, + status, + species, + natureOfComplaint, + violationType, + } = filters; + + const common = { + sortColumn: sortKey, + sortOrder: sortDirection, + regionCodeFilter: region, + zoneCodeFilter: zone, + areaCodeFilter: community, + officerFilter: officer, + startDateFilter: startDate, + endDateFilter: endDate, + complaintStatusFilter: status, + }; + + switch (complaintType) { + case COMPLAINT_TYPES.ERS: + return { + ...common, + violationFilter: violationType, + } as ComplaintRequestPayload; + case COMPLAINT_TYPES.HWCR: + default: + return { + ...common, + speciesCodeFilter: species, + natureOfComplaintFilter: natureOfComplaint, + } as ComplaintRequestPayload; + } +}; + export const ComplaintMap: FC = ({ type, searchQuery }) => { const dispatch = useAppDispatch(); @@ -30,7 +77,7 @@ export const ComplaintMap: FC = ({ type, searchQuery }) => { const [sortDirection, setSortDirection] = useState(SORT_TYPES.DESC); useEffect(() => { - let payload = generateComplaintRequestPayload(type, filters); + let payload = generateMapComplaintRequestPayload(type, filters, sortKey, sortDirection); if (searchQuery) { payload = { ...payload, query: searchQuery }; @@ -39,52 +86,6 @@ export const ComplaintMap: FC = ({ type, searchQuery }) => { dispatch(getComplaintsOnMap(type, payload)); }, [filters, searchQuery]); - - const generateComplaintRequestPayload = ( - complaintType: string, - filters: ComplaintFilters, - ): ComplaintRequestPayload => { - const { - region, - zone, - community, - officer, - startDate, - endDate, - status, - species, - natureOfComplaint, - violationType, - } = filters; - - const common = { - sortColumn: sortKey, - sortOrder: sortDirection, - regionCodeFilter: region, - zoneCodeFilter: zone, - areaCodeFilter: community, - officerFilter: officer, - startDateFilter: startDate, - endDateFilter: endDate, - complaintStatusFilter: status, - }; - - switch (complaintType) { - case COMPLAINT_TYPES.ERS: - return { - ...common, - violationFilter: violationType, - } as ComplaintRequestPayload; - case COMPLAINT_TYPES.HWCR: - default: - return { - ...common, - speciesCodeFilter: species, - natureOfComplaintFilter: natureOfComplaint, - } as ComplaintRequestPayload; - } - }; - useEffect(() => { //-- when the component unmounts clear the complaint from redux return () => { diff --git a/frontend/src/app/components/mapping/leaflet-map-with-multiple-points.tsx b/frontend/src/app/components/mapping/leaflet-map-with-multiple-points.tsx index 6c2b22b93..f50cc867f 100644 --- a/frontend/src/app/components/mapping/leaflet-map-with-multiple-points.tsx +++ b/frontend/src/app/components/mapping/leaflet-map-with-multiple-points.tsx @@ -89,6 +89,7 @@ const LeafletMapWithMultiplePoints: React.FC = ({ return ( Date: Fri, 3 Nov 2023 16:17:01 -0700 Subject: [PATCH 3/3] minor update to search input --- .../app/components/common/search-input.tsx | 53 +++++++++++-------- 1 file changed, 32 insertions(+), 21 deletions(-) diff --git a/frontend/src/app/components/common/search-input.tsx b/frontend/src/app/components/common/search-input.tsx index d14c10690..e65ea367a 100644 --- a/frontend/src/app/components/common/search-input.tsx +++ b/frontend/src/app/components/common/search-input.tsx @@ -1,4 +1,11 @@ -import { ChangeEvent, FC, KeyboardEvent, useContext, useState, useEffect } from "react"; +import { + ChangeEvent, + FC, + KeyboardEvent, + useContext, + useState, + useEffect, +} from "react"; import { InputGroup } from "react-bootstrap"; import { ComplaintFilterContext } from "../../providers/complaint-filter-provider"; import { getComplaints } from "../../store/reducers/complaints"; @@ -26,32 +33,36 @@ const SearchInput: FC = ({ const [input, setInput] = useState(""); - useEffect(() => { - if(!searchQuery){ - setInput("") - } - }, [searchQuery]) + useEffect(() => { + if (!searchQuery) { + setInput(""); + } + }, [searchQuery]); const handleSearch = () => { if (input.length >= 3) { applySearchQuery(input); - let payload = generateComplaintRequestPayload( - complaintType, - filters, - 1, - 50, - "incident_reported_utc_timestmp", - SORT_TYPES.DESC - ); + if (viewType === "list") { + let payload = generateComplaintRequestPayload( + complaintType, + filters, + 1, + 50, + "incident_reported_utc_timestmp", + SORT_TYPES.DESC + ); - payload = { ...payload, query: input }; + payload = { ...payload, query: input }; - if(viewType === "list"){ dispatch(getComplaints(complaintType, payload)); - } - else { - let payload = generateMapComplaintRequestPayload(complaintType, filters, "", ""); + } else { + let payload = generateMapComplaintRequestPayload( + complaintType, + filters, + "", + "" + ); if (searchQuery) { payload = { ...payload, query: searchQuery }; @@ -85,8 +96,8 @@ const SearchInput: FC = ({ if (!value) { handleClear(); - } - + } + setInput(value); };