Skip to content

Commit

Permalink
Psp-8018: For all files do not include a retired property on selection (
Browse files Browse the repository at this point in the history
#4117)

* psp-8018 - display error when selecting retired properties on the map.

* WIP

* remove unused state.

* lint

* ensure multipolygons are still saved.

* geometry is null.

* test corrections.

---------

Co-authored-by: Alejandro Sanchez <[email protected]>
  • Loading branch information
devinleighsmith and asanchezr committed Jun 20, 2024
1 parent d579b05 commit 6766e38
Show file tree
Hide file tree
Showing 57 changed files with 840 additions and 607 deletions.
11 changes: 9 additions & 2 deletions source/frontend/src/components/common/form/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ type OptionalAttributes = {
style?: CSSProperties;
/** override for the autoComplete attribute */
autoSetting?: string;
/** extra error keys to display */
errorKeys?: string[];
};

// only "field" is required for <Input>, the rest are optional
Expand Down Expand Up @@ -74,14 +76,19 @@ export const Input: React.FC<React.PropsWithChildren<InputProps>> = ({
displayErrorTooltips,
onChange,
autoSetting,
errorKeys,
...rest
}) => {
const { handleChange, handleBlur, errors, touched, values, setFieldValue } =
useFormikContext<any>();
const error = getIn(errors, field);
const extraErrors = errorKeys?.map(key => getIn(errors, key)).filter(e => e) ?? [];
const touch = getIn(touched, field);
const value = getIn(values, field);
const errorTooltip = error && touch && displayErrorTooltips ? error : undefined;
const errorTooltip =
(error || extraErrors) && touch && displayErrorTooltips
? (error ? [error, ...extraErrors] : extraErrors).join('\n')
: undefined;
const asElement: any = is || 'input';
const [restricted, setRestricted] = useState(onBlurFormatter ? onBlurFormatter(value) : value);
const handleRestrictedChange = (event: any) => {
Expand Down Expand Up @@ -131,7 +138,7 @@ export const Input: React.FC<React.PropsWithChildren<InputProps>> = ({
style={style}
disabled={disabled}
custom={custom}
isInvalid={!!touch && !!error}
isInvalid={!!touch && (!!error || extraErrors.length > 0)}
{...rest}
isValid={false}
value={pattern ? restricted : rest.value ?? value ?? defaultValue}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ export const MapStateMachineProvider: React.FC<React.PropsWithChildren<unknown>>

const getQueryParams = (filter: IPropertyFilter): IGeoSearchParams => {
// The map will search for either identifier.
const pinOrPidValue = filter.pinOrPid ? filter.pinOrPid?.replace(/-/g, '') : undefined;
const pinOrPidValue = filter.pinOrPid ? filter.pinOrPid?.replaceAll(/-/g, '') : undefined;
return {
PID_PADDED: pinOrPidValue,
PID: pinOrPidValue,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import { usePrevious } from '@/hooks/usePrevious';
import useDeepCompareEffect from '@/hooks/util/useDeepCompareEffect';
import { featuresetToMapProperty } from '@/utils/mapPropertyUtils';

import { IMapProperty } from './models';
import { LocationFeatureDataset } from '../common/mapFSM/useLocationFeatureLoader';

interface IMapClickMonitorProps {
addProperty: (property: IMapProperty) => void; // TODO: This should be a featureDataset
modifiedProperties: IMapProperty[]; // TODO: this should be just a list of lat longs
addProperty: (property: LocationFeatureDataset) => void; // TODO: This should be a featureDataset
modifiedProperties: LocationFeatureDataset[]; // TODO: this should be just a list of lat longs
selectedComponentId: string | null;
}

Expand All @@ -18,7 +18,8 @@ export const MapClickMonitor: React.FunctionComponent<
const mapMachine = useMapStateMachine();

const previous = usePrevious(mapMachine.mapLocationFeatureDataset);
useDraftMarkerSynchronizer(selectedComponentId ? [] : modifiedProperties); // disable the draft marker synchronizer if the selecting component is set - the parent will need to control the draft markers.
const modifiedMapProperties = modifiedProperties.map(mp => featuresetToMapProperty(mp));
useDraftMarkerSynchronizer(selectedComponentId ? [] : modifiedMapProperties); // disable the draft marker synchronizer if the selecting component is set - the parent will need to control the draft markers.

useDeepCompareEffect(() => {
if (
Expand All @@ -29,7 +30,7 @@ export const MapClickMonitor: React.FunctionComponent<
(!selectedComponentId ||
selectedComponentId === mapMachine.mapLocationFeatureDataset.selectingComponentId)
) {
addProperty(featuresetToMapProperty(mapMachine.mapLocationFeatureDataset));
addProperty(mapMachine.mapLocationFeatureDataset);
}
}, [addProperty, mapMachine.isSelecting, mapMachine.mapLocationFeatureDataset, previous]);
return <></>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,13 @@ import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';

import { mockFAParcelLayerResponse, mockGeocoderOptions } from '@/mocks/index.mock';
import { mapMachineBaseMock } from '@/mocks/mapFSM.mock';
import { featuresToIdentifiedMapProperty } from '@/utils/mapPropertyUtils';
import { fillInput, render, RenderOptions, userEvent } from '@/utils/test-utils';

import { PropertyForm } from '../../features/mapSideBar/shared/models';
import { useMapStateMachine } from '../common/mapFSM/MapStateMachineContext';
import MapSelectorContainer, { IMapSelectorContainerProps } from './MapSelectorContainer';
import { IMapProperty } from './models';
import { getMockLocationFeatureDataset } from '@/mocks/featureset.mock';
import { useMapProperties } from '@/hooks/repositories/useMapProperties';

const mockStore = configureMockStore([thunk]);

Expand All @@ -36,6 +35,19 @@ const testProperty: IMapProperty = {
districtName: 'Okanagan-Shuswap',
};

vi.mock('@/hooks/repositories/useMapProperties');
vi.mocked(useMapProperties).mockReturnValue({
loadProperties: {
error: null,
response: { features: [] } as any,
execute: vi.fn().mockResolvedValue({
features: [PropertyForm.fromMapProperty(testProperty).toFeatureDataset().pimsFeature],
}),
loading: false,
status: 200,
},
});

describe('MapSelectorContainer component', () => {
const setup = (renderOptions: RenderOptions & Partial<IMapSelectorContainerProps>) => {
// render component under test
Expand Down Expand Up @@ -70,10 +82,6 @@ describe('MapSelectorContainer component', () => {
.reply(200, mockGeocoderOptions[0]);
});

afterEach(() => {
vi.resetAllMocks();
});

it('renders as expected when provided no properties', async () => {
const { asFragment } = setup({});
await act(async () => {
Expand Down Expand Up @@ -104,14 +112,14 @@ describe('MapSelectorContainer component', () => {

it('displays all selected property attributes', async () => {
const { getByText } = setup({
modifiedProperties: [PropertyForm.fromMapProperty(testProperty)],
modifiedProperties: [PropertyForm.fromMapProperty(testProperty).toFeatureDataset()],
});
await act(async () => {
expect(getByText(/SPS22411/i)).toBeVisible();
expect(getByText(/Test address 123/i)).toBeVisible();
expect(getByText(/1 - South Coast/i)).toBeVisible();
expect(getByText(/5 - Okanagan-Shuswap/i)).toBeVisible();
expect(getByText(/Test Legal Description/i)).toBeVisible();
expect(getByText(/SPS22411/i, { exact: false })).toBeVisible();
expect(getByText(/Test address 123/i, { exact: false })).toBeVisible();
expect(getByText(/1 - South Coast/i, { exact: false })).toBeVisible();
expect(getByText(/5 - Okanagan-Shuswap/i, { exact: false })).toBeVisible();
expect(getByText(/Test Legal Description/i, { exact: false })).toBeVisible();
});
});

Expand All @@ -135,32 +143,130 @@ describe('MapSelectorContainer component', () => {

expect(onSelectedProperties).toHaveBeenCalledWith([
{
address: '1234 Fake St',
areaUnit: 'M2',
district: 12,
districtName: 'Cannot determine',
parcelFeature: {
type: 'Feature',
id: 'PMBC_PARCEL_POLYGON_FABRIC.551',
geometry: {
type: 'Polygon',
coordinates: [
[
[-123.46, 48.767],
[-123.4601, 48.7668],
[-123.461, 48.7654],
[-123.4623, 48.7652],
[-123.4627, 48.7669],
[-123.4602, 48.7672],
[-123.4601, 48.7672],
[-123.4601, 48.7672],
[-123.46, 48.767],
],
],
},
geometry_name: 'SHAPE',
properties: {
GLOBAL_UID: '{4C4D758A-1261-44C1-8835-0FEB93150495}',
PARCEL_NAME: '009727493',
PLAN_ID: 3,
PLAN_NUMBER: 'NO_PLAN',
PIN: null,
PID: '9727493',
PID_NUMBER: null,
SOURCE_PARCEL_ID: null,
PARCEL_STATUS: 'ACTIVE',
PARCEL_CLASS: 'SUBDIVISION',
OWNER_TYPE: 'CROWN PROVINCIAL',
PARCEL_START_DATE: null,
SURVEY_DESIGNATION_1: 'PART 13',
SURVEY_DESIGNATION_2: 'SOUTH SALT SPRING,1',
SURVEY_DESIGNATION_3: '',
LEGAL_DESCRIPTION:
'THAT PART OF SECTION 13, RANGE 1, SOUTH SALT SPRING ISLAND, COWICHAN DISTRICT',
MUNICIPALITY: '0163',
REGIONAL_DISTRICT: '0005',
IS_REMAINDER_IND: 'NO',
GEOMETRY_SOURCE: 'MODIFIED-ICIS',
POSITIONAL_ERROR: 2,
ERROR_REPORTED_BY: 'DATACOMPILATION',
CAPTURE_METHOD: 'UNKNOWN',
COMPILED_IND: '1',
STATED_AREA: null,
WHEN_CREATED: '2016-01-06T17:44:42Z',
WHEN_UPDATED: '2019-01-05T10:21:32Z',
FEATURE_AREA_SQM: 29217,
FEATURE_LENGTH_M: 702,
OBJECTID: 551,
SE_ANNO_CAD_DATA: null,
},
bbox: [-123.4627, 48.7652, -123.46, 48.7672],
},
selectingComponentId: null,
pimsFeature: {
geometry: null,
properties: {
ADDRESS_ID: null,
COUNTRY_CODE: null,
COUNTRY_NAME: null,
DESCRIPTION: null,
DISTRICT_CODE: 5,
ENCUMBRANCE_REASON: null,
HAS_ACTIVE_ACQUISITION_FILE: null,
HAS_ACTIVE_RESEARCH_FILE: null,
HISTORICAL_FILE_NUMBER_STR: null,
IS_ACTIVE_PAYABLE_LEASE: null,
IS_ACTIVE_RECEIVABLE_LEASE: null,
IS_DISPOSED: null,
IS_OTHER_INTEREST: null,
IS_OWNED: null,
IS_PAYABLE_LEASE: null,
IS_RECEIVABLE_LEASE: null,
IS_RETIRED: undefined,
IS_SENSITIVE: null,
IS_VISIBLE_TO_OTHER_AGENCIES: null,
LAND_AREA: undefined,
LAND_LEGAL_DESCRIPTION: 'Test Legal Description',
MUNICIPALITY_NAME: undefined,
NAME: undefined,
PID: 123456789,
PID_PADDED: '123-456-789',
PIN: null,
POSTAL_CODE: undefined,
PROPERTY_AREA_UNIT_TYPE_CODE: undefined,
PROPERTY_CLASSIFICATION_TYPE_CODE: null,
PROPERTY_DATA_SOURCE_EFFECTIVE_DATE: null,
PROPERTY_DATA_SOURCE_TYPE_CODE: null,
PROPERTY_ID: 123,
PROPERTY_STATUS_TYPE_CODE: null,
PROPERTY_TENURE_TYPE_CODE: null,
PROPERTY_TYPE_CODE: null,
PROVINCE_NAME: null,
PROVINCE_STATE_CODE: null,
REGION_CODE: 1,
STREET_ADDRESS_1: 'Test address 123',
STREET_ADDRESS_2: undefined,
STREET_ADDRESS_3: undefined,
SURVEY_PLAN_NUMBER: 'SPS22411',
ZONING: null,
ZONING_POTENTIAL: null,
},
type: 'Feature',
},
location: {
lat: 48.76613749999999,
lng: -123.46163749999998,
},
regionFeature: {},
districtFeature: {},
municipalityFeature: null,
id: 'PID-009-727-493',
landArea: 29217,
latitude: 48.76613749999999,
longitude: -123.46163749999998,
legalDescription:
'THAT PART OF SECTION 13, RANGE 1, SOUTH SALT SPRING ISLAND, COWICHAN DISTRICT',
name: undefined,
pid: '9727493',
pin: undefined,
planNumber: 'NO_PLAN',
propertyId: undefined,
region: 4,
regionName: 'Cannot determine',
},
]);
});

it('selected properties display a warning if added multiple times', async () => {
const { getByText, getByTitle, findByTestId, container } = setup({
modifiedProperties: featuresToIdentifiedMapProperty(mockFAParcelLayerResponse as any)?.map(
p => PropertyForm.fromMapProperty(p),
),
modifiedProperties: [
PropertyForm.fromMapProperty({ ...testProperty, pid: '009-727-493' }).toFeatureDataset(),
],
});

const searchTab = getByText('Search');
Expand Down
Loading

0 comments on commit 6766e38

Please sign in to comment.