Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/dev' into release/uat_is92
Browse files Browse the repository at this point in the history
  • Loading branch information
asanchezr committed Nov 7, 2024
2 parents cf116f2 + 681193a commit 64acc43
Show file tree
Hide file tree
Showing 29 changed files with 328 additions and 150 deletions.
4 changes: 2 additions & 2 deletions source/backend/api/Pims.Api.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<UserSecretsId>0ef6255f-9ea0-49ec-8c65-c172304b4926</UserSecretsId>
<Version>5.6.0-92.30</Version>
<Version>5.6.0-92.30</Version>
<Version>5.6.0-92.35</Version>
<Version>5.6.0-92.35</Version>
<AssemblyVersion>5.6.0.92</AssemblyVersion>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<ProjectGuid>16BC0468-78F6-4C91-87DA-7403C919E646</ProjectGuid>
Expand Down
2 changes: 1 addition & 1 deletion source/frontend/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "frontend",
"version": "5.6.0-92.30",
"version": "5.6.0-92.35",
"private": true,
"dependencies": {
"@bcgov/bc-sans": "1.0.1",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { useInterpret, useSelector } from '@xstate/react';
import { dequal } from 'dequal';
import { LatLngBounds, LatLngLiteral } from 'leaflet';
import React, { useCallback, useMemo } from 'react';
import { useHistory } from 'react-router-dom';

import { PropertyFilterFormModel } from '@/components/maps/leaflet/Control/AdvancedFilter/models';
import { ILayerItem } from '@/components/maps/leaflet/Control/LayersControl/types';
import { IGeoSearchParams } from '@/constants/API';
import { IMapSideBarViewState } from '@/features/mapSideBar/MapSideBar';
Expand Down Expand Up @@ -46,6 +48,9 @@ export interface IMapStateMachineContext {
showDisposed: boolean;
showRetired: boolean;
activeLayers: ILayerItem[];
mapLayersToRefresh: ILayerItem[];
advancedSearchCriteria: PropertyFilterFormModel;
isMapVisible: boolean;

requestFlyToLocation: (latlng: LatLngLiteral) => void;
requestFlyToBounds: (bounds: LatLngBounds) => void;
Expand Down Expand Up @@ -74,13 +79,15 @@ export interface IMapStateMachineContext {
toggleMapLayerControl: () => void;
setFilePropertyLocations: (locations: LatLngLiteral[]) => void;
setMapLayers: (layers: ILayerItem[]) => void;
setMapLayersToRefresh: (layers: ILayerItem[]) => void;
setDefaultMapLayers: (layers: ILayerItem[]) => void;

setVisiblePimsProperties: (propertyIds: number[]) => void;
setShowDisposed: (show: boolean) => void;
setShowRetired: (show: boolean) => void;
setFullWidthSideBar: (fullWidth: boolean) => void;
resetMapFilter: () => void;
setAdvancedSearchCriteria: (advancedSearchCriteria: PropertyFilterFormModel) => void;
}

const MapStateMachineContext = React.createContext<IMapStateMachineContext>(
Expand Down Expand Up @@ -250,6 +257,13 @@ export const MapStateMachineProvider: React.FC<React.PropsWithChildren<unknown>>
[serviceSend],
);

const setAdvancedSearchCriteria = useCallback(
(advancedSearchCriteria: PropertyFilterFormModel) => {
serviceSend({ type: 'SET_ADVANCED_SEARCH_CRITERIA', advancedSearchCriteria });
},
[serviceSend],
);

const prepareForCreation = useCallback(() => {
serviceSend({ type: 'PREPARE_FOR_CREATION' });
}, [serviceSend]);
Expand Down Expand Up @@ -299,6 +313,13 @@ export const MapStateMachineProvider: React.FC<React.PropsWithChildren<unknown>>
[serviceSend],
);

const setMapLayersToRefresh = useCallback(
(refreshLayers: ILayerItem[]) => {
serviceSend({ type: 'SET_REFRESH_MAP_LAYERS', refreshLayers });
},
[serviceSend],
);

const setDefaultMapLayers = useCallback(
(activeLayers: ILayerItem[]) => {
serviceSend({ type: 'DEFAULT_MAP_LAYERS', activeLayers });
Expand Down Expand Up @@ -371,7 +392,12 @@ export const MapStateMachineProvider: React.FC<React.PropsWithChildren<unknown>>
<MapStateMachineContext.Provider
value={{
mapSideBarViewState: state.context.mapSideBarState,
isShowingSearchBar: !state.context.mapSideBarState.isOpen && !state.context.isFiltering,
isShowingSearchBar:
!state.context.mapSideBarState.isOpen &&
!(
isShowingMapFilter ||
!dequal(state.context.advancedSearchCriteria, new PropertyFilterFormModel())
),
pendingFlyTo: state.matches({ mapVisible: { mapRequest: 'pendingFlyTo' } }),
requestedFlyTo: state.context.requestedFlyTo,
mapFeatureSelected: state.context.mapFeatureSelected,
Expand All @@ -383,20 +409,23 @@ export const MapStateMachineProvider: React.FC<React.PropsWithChildren<unknown>>
showPopup: showPopup,
isLoading: state.context.isLoading,
mapSearchCriteria: state.context.searchCriteria,
advancedSearchCriteria: state.context.advancedSearchCriteria,
mapFeatureData: state.context.mapFeatureData,
filePropertyLocations: state.context.filePropertyLocations,
pendingFitBounds: state.matches({ mapVisible: { mapRequest: 'pendingFitBounds' } }),
requestedFitBounds: state.context.requestedFitBounds,
isSelecting: state.matches({ mapVisible: { featureView: 'selecting' } }),
isRepositioning: isRepositioning,
selectingComponentId: state.context.selectingComponentId,
isFiltering: state.context.isFiltering,
isFiltering: !dequal(state.context.advancedSearchCriteria, new PropertyFilterFormModel()),
isShowingMapFilter: isShowingMapFilter,
isShowingMapLayers: isShowingMapLayers,
activeLayers: state.context.activeLayers,
activePimsPropertyIds: state.context.activePimsPropertyIds,
showDisposed: state.context.showDisposed,
showRetired: state.context.showRetired,
mapLayersToRefresh: state.context.mapLayersToRefresh,
isMapVisible: state.matches({ mapVisible: {} }),

setMapSearchCriteria,
refreshMapProperties,
Expand All @@ -422,9 +451,11 @@ export const MapStateMachineProvider: React.FC<React.PropsWithChildren<unknown>>
setShowDisposed,
setShowRetired,
setMapLayers,
setMapLayersToRefresh,
setDefaultMapLayers,
setFullWidthSideBar,
resetMapFilter,
setAdvancedSearchCriteria,
}}
>
{children}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { latLngBounds } from 'leaflet';
import { assign, createMachine, raise, send } from 'xstate';

import { defaultBounds } from '@/components/maps/constants';
import { PropertyFilterFormModel } from '@/components/maps/leaflet/Control/AdvancedFilter/models';
import { PIMS_PROPERTY_BOUNDARY_KEY } from '@/components/maps/leaflet/Control/LayersControl/data';
import { defaultPropertyFilter } from '@/features/properties/filter/IPropertyFilter';

import { emptyFeatureData } from '../models';
Expand Down Expand Up @@ -84,6 +86,9 @@ const featureDataLoaderStates = {
}),
target: 'loading',
},
SET_REFRESH_MAP_LAYERS: {
actions: assign({ mapLayersToRefresh: (_, event: any) => event.refreshLayers }),
},
},
},
loading: {
Expand All @@ -97,6 +102,7 @@ const featureDataLoaderStates = {
isLoading: () => false,
mapFeatureData: (_, event: any) => event.data,
fitToResultsAfterLoading: () => false,
mapLayersToRefresh: () => [{ key: PIMS_PROPERTY_BOUNDARY_KEY }],
}),
raise('REQUEST_FIT_BOUNDS'),
],
Expand All @@ -108,6 +114,7 @@ const featureDataLoaderStates = {
isLoading: () => false,
mapFeatureData: (_, event: any) => event.data,
fitToResultsAfterLoading: () => false,
mapLayersToRefresh: () => [{ key: PIMS_PROPERTY_BOUNDARY_KEY }],
}),
],
target: 'idle',
Expand Down Expand Up @@ -367,16 +374,17 @@ const advancedFilterSideBarStates = {
},
},
mapFilterOpened: {
entry: [assign({ isFiltering: () => true })],
on: {
TOGGLE_FILTER: {
target: 'closed',
},
TOGGLE_LAYERS: {
target: 'layerControl',
},
SET_VISIBLE_PROPERTIES: {
actions: assign({ activePimsPropertyIds: (_, event: any) => event.propertyIds }),
SET_ADVANCED_SEARCH_CRITERIA: {
actions: assign({
advancedSearchCriteria: (_, event: any) => event.advancedSearchCriteria,
}),
},
SET_SHOW_DISPOSED: {
actions: assign({ showDisposed: (_, event: any) => event.show }),
Expand Down Expand Up @@ -430,13 +438,15 @@ export const mapMachine = createMachine<MachineContext>({
isLoading: false,
fitToResultsAfterLoading: false,
searchCriteria: null,
advancedSearchCriteria: new PropertyFilterFormModel(),
mapFeatureData: emptyFeatureData,
filePropertyLocations: [],
activePimsPropertyIds: [],
isFiltering: false,
showDisposed: false,
showRetired: false,
activeLayers: [],
mapLayersToRefresh: [],
},

// State definitions
Expand Down Expand Up @@ -489,6 +499,9 @@ export const mapMachine = createMachine<MachineContext>({
DEFAULT_MAP_LAYERS: {
actions: assign({ activeLayers: (_, event: any) => event.activeLayers }),
},
SET_VISIBLE_PROPERTIES: {
actions: assign({ activePimsPropertyIds: (_, event: any) => event.propertyIds }),
},
},
states: {
featureView: featureViewStates,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { LatLngBounds, LatLngLiteral } from 'leaflet';

import { PropertyFilterFormModel } from '@/components/maps/leaflet/Control/AdvancedFilter/models';
import { ILayerItem } from '@/components/maps/leaflet/Control/LayersControl/types';
import { IMapSideBarViewState as IMapSideBarState } from '@/features/mapSideBar/MapSideBar';
import { IPropertyFilter } from '@/features/properties/filter/IPropertyFilter';
Expand Down Expand Up @@ -35,6 +36,7 @@ export type MachineContext = {

// TODO: this is partially in the URL. Either move it completly there or remove it
searchCriteria: IPropertyFilter | null;
advancedSearchCriteria: PropertyFilterFormModel | null;

isLoading: boolean;
fitToResultsAfterLoading: boolean;
Expand All @@ -43,6 +45,7 @@ export type MachineContext = {
filePropertyLocations: LatLngLiteral[];
activePimsPropertyIds: number[];
activeLayers: ILayerItem[];
mapLayersToRefresh: ILayerItem[];
isFiltering: boolean;
showDisposed: boolean;
showRetired: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,6 @@ const storeState = {
[lookupCodesSlice.name]: { lookupCodes: mockLookups },
};

const mockGetApi = {
error: undefined,
response: [1] as number[] | undefined,
execute: vi.fn().mockResolvedValue([1]),
loading: false,
};
vi.mock('@/hooks/repositories/usePimsPropertyRepository', () => ({
usePimsPropertyRepository: () => {
return {
getMatchingProperties: mockGetApi,
};
},
}));

describe('FilterContentContainer component', () => {
let viewProps: IFilterContentFormProps;

Expand All @@ -46,7 +32,7 @@ describe('FilterContentContainer component', () => {
...renderOptions,
store: storeState,
history,
mockMapMachine: { ...mapMachineBaseMock, isFiltering: true },
mockMapMachine: { ...mapMachineBaseMock, isFiltering: false, isShowingMapFilter: true },
});

return {
Expand All @@ -62,12 +48,13 @@ describe('FilterContentContainer component', () => {
vi.clearAllMocks();
});

it('fetches filter data from the api', async () => {
mockGetApi.execute.mockResolvedValue([1, 2]);
it('fetches filter data from the api if filter changed', async () => {
setup({});
await act(async () => viewProps.onChange(new PropertyFilterFormModel()));
expect(mockGetApi.execute).toHaveBeenCalledWith(new PropertyFilterFormModel().toApi());
expect(mapMachineBaseMock.setVisiblePimsProperties).toHaveBeenCalledWith([1, 2]);
const filter = new PropertyFilterFormModel();
filter.isRetired = true;

await act(async () => viewProps.onChange(filter));
expect(mapMachineBaseMock.setAdvancedSearchCriteria).toHaveBeenCalledWith(filter);
});

it(`resets the map filter state when "onReset" is called`, async () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import React, { useCallback } from 'react';

import { useMapStateMachine } from '@/components/common/mapFSM/MapStateMachineContext';
import { usePimsPropertyRepository } from '@/hooks/repositories/usePimsPropertyRepository';
import { Api_PropertyFilterCriteria } from '@/models/api/ProjectFilterCriteria';

import { IFilterContentFormProps } from './FilterContentForm';
import { PropertyFilterFormModel } from './models';
Expand All @@ -12,40 +10,33 @@ export interface IFilterContentContainerProps {
}

export const FilterContentContainer: React.FC<IFilterContentContainerProps> = ({ View }) => {
const { isFiltering, setVisiblePimsProperties, setShowDisposed, setShowRetired, resetMapFilter } =
useMapStateMachine();

const { getMatchingProperties } = usePimsPropertyRepository();

const matchProperties = getMatchingProperties.execute;

const filterProperties = useCallback(
async (filter: Api_PropertyFilterCriteria) => {
const retrievedProperties = await matchProperties(filter);

if (retrievedProperties !== undefined) {
setVisiblePimsProperties(retrievedProperties);
}
},
[matchProperties, setVisiblePimsProperties],
);
const {
setShowDisposed,
setShowRetired,
resetMapFilter,
setAdvancedSearchCriteria,
isShowingMapFilter,
isLoading,
advancedSearchCriteria,
} = useMapStateMachine();

const onChange = useCallback(
async (model: PropertyFilterFormModel) => {
await filterProperties(model.toApi());
setAdvancedSearchCriteria(model);
setShowDisposed(model.isDisposed);
setShowRetired(model.isRetired);
},
[filterProperties, setShowDisposed, setShowRetired],
[setShowDisposed, setShowRetired, setAdvancedSearchCriteria],
);

// Only render if the map state is filtering.
if (isFiltering) {
if (isShowingMapFilter) {
return (
<View
existingFilter={advancedSearchCriteria}
onChange={onChange}
onReset={resetMapFilter}
isLoading={getMatchingProperties.loading}
isLoading={isLoading}
/>
);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { lookupCodesSlice } from '@/store/slices/lookupCodes';
import { act, render, RenderOptions, userEvent } from '@/utils/test-utils';

import { FilterContentForm, IFilterContentFormProps } from './FilterContentForm';
import { PropertyFilterFormModel } from './models';

const history = createMemoryHistory();
const storeState = {
Expand All @@ -25,6 +26,7 @@ describe('FilterContentForm component', () => {
isLoading={renderOptions?.props?.isLoading ?? false}
onChange={renderOptions?.props?.onChange ?? onChange}
onReset={renderOptions?.props?.onReset ?? onReset}
existingFilter={renderOptions?.props?.existingFilter ?? new PropertyFilterFormModel()}
/>,
{
...renderOptions,
Expand Down
Loading

0 comments on commit 64acc43

Please sign in to comment.