diff --git a/source/frontend/src/components/common/mapFSM/MapStateMachineContext.tsx b/source/frontend/src/components/common/mapFSM/MapStateMachineContext.tsx index df3f4ce05b..f44e0e1bb9 100644 --- a/source/frontend/src/components/common/mapFSM/MapStateMachineContext.tsx +++ b/source/frontend/src/components/common/mapFSM/MapStateMachineContext.tsx @@ -83,10 +83,10 @@ export const MapStateMachineProvider: React.FC> actions: { navigateToProperty: (context, event: any) => { const selectedFeatureData = context.mapLocationFeatureDataset; - if (selectedFeatureData?.pimsFeature?.properties.PROPERTY_ID) { + if (selectedFeatureData?.pimsFeature?.properties?.PROPERTY_ID) { const pimsFeature = selectedFeatureData.pimsFeature; history.push(`/mapview/sidebar/property/${pimsFeature.properties.PROPERTY_ID}`); - } else if (selectedFeatureData?.parcelFeature?.properties.PID) { + } else if (selectedFeatureData?.parcelFeature?.properties?.PID) { const parcelFeature = selectedFeatureData.parcelFeature; const parsedPid = pidParser(parcelFeature.properties.PID); history.push(`/mapview/sidebar/non-inventory-property/${parsedPid}`); diff --git a/source/frontend/src/components/maps/leaflet/Layers/util.tsx b/source/frontend/src/components/maps/leaflet/Layers/util.tsx index 47dc75b1ae..d9b8f41271 100644 --- a/source/frontend/src/components/maps/leaflet/Layers/util.tsx +++ b/source/frontend/src/components/maps/leaflet/Layers/util.tsx @@ -79,6 +79,30 @@ export const otherInterestIconSelect = L.icon({ shadowSize: [41, 41], }); +// not owned property icon (orange) +export const notOwnedPropertyIcon = L.icon({ + iconUrl: + require('@/assets/images/pins/marker-info-orange.png') ?? + 'assets/images/pins/marker-info-orange.png', + shadowUrl: require('@/assets/images/pins/marker-shadow.png') ?? 'marker-shadow.png', + iconSize: [25, 41], + iconAnchor: [12, 41], + popupAnchor: [1, -34], + shadowSize: [41, 41], +}); + +// not owned property icon (orange) highlighted +export const notOwnedPropertyIconSelect = L.icon({ + iconUrl: + require('@/assets/images/pins/marker-info-orange-highlight.png') ?? + 'assets/images/pins/marker-info-orange-highlight.png', + shadowUrl: require('@/assets/images/pins/marker-shadow.png') ?? 'marker-shadow.png', + iconSize: [25, 41], + iconAnchor: [12, 41], + popupAnchor: [1, -34], + shadowSize: [41, 41], +}); + /** * Creates map points (in GeoJSON format) for further clustering by `supercluster` * @param properties @@ -154,6 +178,16 @@ export function getMarkerIcon( } } +/** + * Get an icon type for the specified cluster property details. + */ +export function getNotOwnerMarkerIcon(selected: boolean): L.Icon { + if (selected) { + return notOwnedPropertyIconSelect; + } + return notOwnedPropertyIcon; +} + // parcel icon (green) highlighted export const getDraftIcon = (text: string) => { return L.divIcon({ @@ -179,8 +213,10 @@ export const createSingleMarker =

( if (isOwned) { const icon = getMarkerIcon(feature, false); return new Marker(latlng, { icon }); + } else { + const icon = getNotOwnerMarkerIcon(false); + return new Marker(latlng, { icon }); } - throw Error('marker type not found'); }; export const isPimsFeature = ( diff --git a/source/frontend/src/components/maps/leaflet/Markers/SingleMarker.tsx b/source/frontend/src/components/maps/leaflet/Markers/SingleMarker.tsx index 1a34155314..b6151795bb 100644 --- a/source/frontend/src/components/maps/leaflet/Markers/SingleMarker.tsx +++ b/source/frontend/src/components/maps/leaflet/Markers/SingleMarker.tsx @@ -11,6 +11,7 @@ import { import { getMarkerIcon, + getNotOwnerMarkerIcon, isFullyAttributed, isPimsBoundary, isPimsFeature, @@ -40,6 +41,7 @@ const SinglePropertyMarker: React.FC = props => { props.setIsEditing(true)} setEditTakes={() => props.setIsEditing(true)} fileProperty={fileProperty} diff --git a/source/frontend/src/features/mapSideBar/property/InventoryTabs.tsx b/source/frontend/src/features/mapSideBar/property/InventoryTabs.tsx index e2ca35d485..26bcb13537 100644 --- a/source/frontend/src/features/mapSideBar/property/InventoryTabs.tsx +++ b/source/frontend/src/features/mapSideBar/property/InventoryTabs.tsx @@ -1,5 +1,6 @@ import * as React from 'react'; import { Tab } from 'react-bootstrap'; +import { generatePath, useHistory, useRouteMatch } from 'react-router-dom'; import TabView from '@/components/common/TabView'; @@ -14,7 +15,6 @@ export interface IInventoryTabsProps { defaultTabKey: InventoryTabNames; tabViews: TabInventoryView[]; activeTab: InventoryTabNames; - setActiveTab: (tab: InventoryTabNames) => void; } export enum InventoryTabNames { @@ -32,16 +32,17 @@ export enum InventoryTabNames { */ export const InventoryTabs: React.FunctionComponent< React.PropsWithChildren -> = ({ defaultTabKey, tabViews, activeTab, setActiveTab }) => { +> = ({ defaultTabKey, tabViews, activeTab }) => { + const history = useHistory(); + const match = useRouteMatch<{ propertyId: string }>(); return ( { const tab = Object.values(InventoryTabNames).find(value => value === eventKey); - if (tab && tab !== activeTab) { - setActiveTab(tab); - } + const path = generatePath(match.path, { propertyId: match.params.propertyId, tab }); + history.push(path); }} > {tabViews.map((view: TabInventoryView, index: number) => ( diff --git a/source/frontend/src/features/mapSideBar/property/MotiInventoryContainer.test.tsx b/source/frontend/src/features/mapSideBar/property/MotiInventoryContainer.test.tsx index 06ec690335..ee4f85095d 100644 --- a/source/frontend/src/features/mapSideBar/property/MotiInventoryContainer.test.tsx +++ b/source/frontend/src/features/mapSideBar/property/MotiInventoryContainer.test.tsx @@ -123,6 +123,7 @@ describe('MotiInventoryContainer component', () => { it('hides the property information tab for non-inventory properties', async () => { mockAxios.onPost().reply(200, {}); + history.push('/mapview/sidebar/non-inventory-property/9212434'); // non-inventory properties will not attempt to contact the backend. const error = { isAxiosError: true, diff --git a/source/frontend/src/features/mapSideBar/property/MotiInventoryContainer.tsx b/source/frontend/src/features/mapSideBar/property/MotiInventoryContainer.tsx index 7e59b96a06..538df53914 100644 --- a/source/frontend/src/features/mapSideBar/property/MotiInventoryContainer.tsx +++ b/source/frontend/src/features/mapSideBar/property/MotiInventoryContainer.tsx @@ -1,17 +1,19 @@ import { FormikProps } from 'formik'; import React, { useEffect, useRef, useState } from 'react'; +import { generatePath, useHistory, useRouteMatch } from 'react-router-dom'; import styled from 'styled-components'; import { ReactComponent as LotSvg } from '@/assets/images/icon-lot.svg'; import GenericModal from '@/components/common/GenericModal'; import { useMapStateMachine } from '@/components/common/mapFSM/MapStateMachineContext'; -import PropertyViewSelector from '@/features/mapSideBar/property/PropertyViewSelector'; import { PROPERTY_TYPES, useComposedProperties } from '@/hooks/repositories/useComposedProperties'; +import { useQuery } from '@/hooks/use-query'; import { Api_Property } from '@/models/api/Property'; import MapSideBarLayout from '../layout/MapSideBarLayout'; import SidebarFooter from '../shared/SidebarFooter'; import { MotiInventoryHeader } from './MotiInventoryHeader'; +import PropertyRouter from './PropertyRouter'; export interface IMotiInventoryContainerProps { id?: number; @@ -27,7 +29,11 @@ export const MotiInventoryContainer: React.FunctionComponent< > = props => { const [showCancelConfirmModal, setShowCancelConfirmModal] = useState(false); - const [isEditing, setIsEditing] = useState(false); + const query = useQuery(); + const { push } = useHistory(); + const match = useRouteMatch(); + const tabMatch = useRouteMatch<{ tab: string; propertyId: string }>(`${match.path}/:tab`); + const isEditing = query.get('edit') === 'true'; const [isValid, setIsValid] = useState(true); const mapMachine = useMapStateMachine(); @@ -48,12 +54,12 @@ export const MotiInventoryContainer: React.FunctionComponent< }); useEffect(() => { - setIsEditing(false); - }, [props.pid]); + push({ search: '' }); + }, [props.pid, push]); const onSuccess = () => { props.id && composedPropertyState.apiWrapper?.execute(props.id); - setIsEditing(false); + stripEditFromPath(); }; const handleSaveClick = async () => { @@ -80,10 +86,22 @@ export const MotiInventoryContainer: React.FunctionComponent< if (formikRef !== undefined) { formikRef.current?.resetForm(); } - setIsEditing(false); + + stripEditFromPath(); setShowCancelConfirmModal(false); }; + const stripEditFromPath = () => { + if (!tabMatch) { + return; + } + const path = generatePath('/mapview/sidebar/property/:propertyId/:tab', { + propertyId: tabMatch?.params.propertyId, + tab: tabMatch?.params.tab, + }); + push(path, { search: query.toString() }); + }; + const handleZoom = (apiProperty?: Api_Property | undefined) => { if (apiProperty?.longitude !== undefined && apiProperty?.latitude !== undefined) { mapMachine.requestFlyToLocation({ lat: apiProperty.latitude, lng: apiProperty.longitude }); @@ -120,10 +138,8 @@ export const MotiInventoryContainer: React.FunctionComponent< onClose={props.onClose} > <> - diff --git a/source/frontend/src/features/mapSideBar/property/PropertyContainer.test.tsx b/source/frontend/src/features/mapSideBar/property/PropertyContainer.test.tsx index d5fc1812c5..57f0785c22 100644 --- a/source/frontend/src/features/mapSideBar/property/PropertyContainer.test.tsx +++ b/source/frontend/src/features/mapSideBar/property/PropertyContainer.test.tsx @@ -37,7 +37,6 @@ describe('PropertyContainer component', () => { const { queryByText } = setup({ claims: [], composedPropertyState: { apiWrapper: { response: {} }, id: 1 } as any, - setEditManagementState: jest.fn(), }); expect(queryByText('Management')).toBeNull(); @@ -47,7 +46,6 @@ describe('PropertyContainer component', () => { const { getByText } = setup({ claims: [Claims.MANAGEMENT_VIEW], composedPropertyState: { apiWrapper: { response: {} }, id: 1 } as any, - setEditManagementState: jest.fn(), }); expect(getByText('Management')).toBeVisible(); diff --git a/source/frontend/src/features/mapSideBar/property/PropertyContainer.tsx b/source/frontend/src/features/mapSideBar/property/PropertyContainer.tsx index 8ad9f48b92..1706609545 100644 --- a/source/frontend/src/features/mapSideBar/property/PropertyContainer.tsx +++ b/source/frontend/src/features/mapSideBar/property/PropertyContainer.tsx @@ -1,4 +1,5 @@ -import React, { useState } from 'react'; +import React from 'react'; +import { useParams } from 'react-router-dom'; import { Claims } from '@/constants'; import { usePropertyDetails } from '@/features/mapSideBar/hooks/usePropertyDetails'; @@ -14,12 +15,10 @@ import { PropertyDetailsTabView } from '@/features/mapSideBar/property/tabs/prop import ComposedPropertyState from '@/hooks/repositories/useComposedProperties'; import useKeycloakWrapper from '@/hooks/useKeycloakWrapper'; -import { EditManagementState } from './PropertyViewSelector'; import { PropertyManagementTabView } from './tabs/propertyDetailsManagement/detail/PropertyManagementTabView'; export interface IPropertyContainerProps { composedPropertyState: ComposedPropertyState; - setEditManagementState: (state: EditManagementState | null) => void; } /** @@ -27,7 +26,7 @@ export interface IPropertyContainerProps { */ export const PropertyContainer: React.FunctionComponent< React.PropsWithChildren -> = ({ composedPropertyState, setEditManagementState }) => { +> = ({ composedPropertyState }) => { const showPropertyInfoTab = composedPropertyState?.id !== undefined; const { hasClaim } = useKeycloakWrapper(); @@ -79,7 +78,6 @@ export const PropertyContainer: React.FunctionComponent< ), key: InventoryTabNames.property, @@ -114,7 +112,6 @@ export const PropertyContainer: React.FunctionComponent< ), key: InventoryTabNames.management, @@ -123,15 +120,14 @@ export const PropertyContainer: React.FunctionComponent< defaultTab = InventoryTabNames.management; } - const [activeTab, setActiveTab] = useState(defaultTab); - + const params = useParams<{ tab?: string }>(); + const activeTab = Object.values(InventoryTabNames).find(t => t === params.tab) ?? defaultTab; return ( ); }; diff --git a/source/frontend/src/features/mapSideBar/property/PropertyRouter.tsx b/source/frontend/src/features/mapSideBar/property/PropertyRouter.tsx new file mode 100644 index 0000000000..80eaadf146 --- /dev/null +++ b/source/frontend/src/features/mapSideBar/property/PropertyRouter.tsx @@ -0,0 +1,134 @@ +import { FormikProps } from 'formik'; +import React from 'react'; +import { Redirect, Switch, useHistory, useRouteMatch } from 'react-router-dom'; + +import { UpdatePropertyDetailsContainer } from '@/features/mapSideBar/property/tabs/propertyDetails/update/UpdatePropertyDetailsContainer'; +import ComposedPropertyState from '@/hooks/repositories/useComposedProperties'; +import { useQuery } from '@/hooks/use-query'; +import { stripTrailingSlash } from '@/utils'; +import AppRoute from '@/utils/AppRoute'; + +import { InventoryTabNames } from './InventoryTabs'; +import PropertyContainer from './PropertyContainer'; +import { PropertyContactEditContainer } from './tabs/propertyDetailsManagement/update/PropertyContactEditContainer'; +import { PropertyContactEditForm } from './tabs/propertyDetailsManagement/update/PropertyContactEditForm'; +import { PropertyManagementUpdateContainer } from './tabs/propertyDetailsManagement/update/summary/PropertyManagementUpdateContainer'; +import { PropertyManagementUpdateForm } from './tabs/propertyDetailsManagement/update/summary/PropertyManagementUpdateForm'; + +export enum PropertyEditForms { + UpdatePropertyDetailsContainer = 'UpdatePropertyDetailsContainer', + UpdateManagementSummaryContainer = 'UpdateManagementSummaryContainer', + UpdateContactContainer = 'UpdateContactContainer', +} + +export interface EditManagementState { + form: PropertyEditForms; + childId: number | null; +} + +export interface IPropertyRouterProps { + onSuccess: () => void; + composedPropertyState: ComposedPropertyState; +} + +const PropertyRouter = React.forwardRef, IPropertyRouterProps>( + (props, formikRef) => { + const query = useQuery(); + const isEditing = query.get('edit') === 'true'; + const { path } = useRouteMatch(); + const history = useHistory(); + + const setIsEditing = (value: boolean) => { + if (value) { + query.set('edit', value.toString()); + } else { + query.delete('edit'); + } + history.push({ search: query.toString() }); + }; + + if (isEditing && !!props?.composedPropertyState?.apiWrapper?.response?.id) { + return ( + + ( + { + setIsEditing(false); + props.onSuccess(); + }} + ref={formikRef} + /> + )} + key={PropertyEditForms.UpdatePropertyDetailsContainer} + title={'Update Property Details'} + > + ( + { + setIsEditing(false); + props.onSuccess(); + }} + ref={formikRef} + /> + )} + key={PropertyEditForms.UpdateContactContainer} + title="Update Contact" + > + ( + { + setIsEditing(false); + props.onSuccess(); + }} + ref={formikRef} + /> + )} + key={PropertyEditForms.UpdateManagementSummaryContainer} + title="Update Management Summary" + > + + ); + } else { + return ( + + ( + + )} + key={'property_tabs'} + title={'Property Tabs'} + > + + + + ); + } + }, +); + +export default PropertyRouter; diff --git a/source/frontend/src/features/mapSideBar/property/PropertyViewSelector.tsx b/source/frontend/src/features/mapSideBar/property/PropertyViewSelector.tsx deleted file mode 100644 index f0b24b7805..0000000000 --- a/source/frontend/src/features/mapSideBar/property/PropertyViewSelector.tsx +++ /dev/null @@ -1,103 +0,0 @@ -import { FormikProps } from 'formik'; -import React, { useEffect, useState } from 'react'; - -import { UpdatePropertyDetailsContainer } from '@/features/mapSideBar/property/tabs/propertyDetails/update/UpdatePropertyDetailsContainer'; -import ComposedPropertyState from '@/hooks/repositories/useComposedProperties'; - -import PropertyContainer from './PropertyContainer'; -import { PropertyContactEditContainer } from './tabs/propertyDetailsManagement/update/PropertyContactEditContainer'; -import { PropertyContactEditForm } from './tabs/propertyDetailsManagement/update/PropertyContactEditForm'; -import { PropertyManagementUpdateContainer } from './tabs/propertyDetailsManagement/update/summary/PropertyManagementUpdateContainer'; -import { PropertyManagementUpdateForm } from './tabs/propertyDetailsManagement/update/summary/PropertyManagementUpdateForm'; - -export enum PropertyEditForms { - UpdatePropertyDetailsContainer = 'UpdatePropertyDetailsContainer', - UpdateManagementSummaryContainer = 'UpdateManagementSummaryContainer', - UpdateContactContainer = 'UpdateContactContainer', -} - -export interface EditManagementState { - form: PropertyEditForms; - childId: number | null; -} - -export interface IPropertyViewSelectorProps { - isEditMode: boolean; - setEditMode: (isEditing: boolean) => void; - onSuccess: () => void; - composedPropertyState: ComposedPropertyState; -} - -const PropertyViewSelector = React.forwardRef, IPropertyViewSelectorProps>( - (props, formikRef) => { - const [editManagementState, setEditManagementState] = useState( - null, - ); - - useEffect(() => { - if (editManagementState === null) { - props.setEditMode(false); - } else { - props.setEditMode(true); - } - }, [editManagementState, props, props.setEditMode]); - - useEffect(() => { - if (props.isEditMode === false) { - setEditManagementState(null); - } - }, [props, props.isEditMode]); - - if (props.isEditMode && !!props?.composedPropertyState?.apiWrapper?.response?.id) { - switch (editManagementState?.form) { - case PropertyEditForms.UpdatePropertyDetailsContainer: - return ( - { - setEditManagementState(null); - props.onSuccess(); - }} - ref={formikRef} - /> - ); - case PropertyEditForms.UpdateManagementSummaryContainer: - return ( - { - setEditManagementState(null); - props.onSuccess(); - }} - ref={formikRef} - /> - ); - case PropertyEditForms.UpdateContactContainer: - return ( - { - setEditManagementState(null); - props.onSuccess(); - }} - ref={formikRef} - /> - ); - default: - return <>; - } - } else { - return ( - - ); - } - }, -); - -export default PropertyViewSelector; diff --git a/source/frontend/src/features/mapSideBar/property/tabs/propertyDetails/detail/PropertyDetailsTabView.test.tsx b/source/frontend/src/features/mapSideBar/property/tabs/propertyDetails/detail/PropertyDetailsTabView.test.tsx index 2dfb11607f..a17ad19894 100644 --- a/source/frontend/src/features/mapSideBar/property/tabs/propertyDetails/detail/PropertyDetailsTabView.test.tsx +++ b/source/frontend/src/features/mapSideBar/property/tabs/propertyDetails/detail/PropertyDetailsTabView.test.tsx @@ -1,5 +1,4 @@ import { createMemoryHistory } from 'history'; -import { noop } from 'lodash'; import { Claims, PropertyTenureTypes } from '@/constants/index'; import { mockLookups } from '@/mocks/lookups.mock'; @@ -23,19 +22,12 @@ describe('PropertyDetailsTabView component', () => { const setup = (renderOptions: RenderOptions & { property?: Api_Property } = {}) => { const { property, ...rest } = renderOptions; const formValues = toFormValues(property); - const component = render( - , - { - ...rest, - store: storeState, - claims: [Claims.PROPERTY_EDIT], - history, - }, - ); + const component = render(, { + ...rest, + store: storeState, + claims: [Claims.PROPERTY_EDIT], + history, + }); return { ...component, diff --git a/source/frontend/src/features/mapSideBar/property/tabs/propertyDetails/detail/PropertyDetailsTabView.tsx b/source/frontend/src/features/mapSideBar/property/tabs/propertyDetails/detail/PropertyDetailsTabView.tsx index 7bfb6800cf..d04c1d016f 100644 --- a/source/frontend/src/features/mapSideBar/property/tabs/propertyDetails/detail/PropertyDetailsTabView.tsx +++ b/source/frontend/src/features/mapSideBar/property/tabs/propertyDetails/detail/PropertyDetailsTabView.tsx @@ -1,6 +1,7 @@ import Multiselect from 'multiselect-react-dropdown'; import React from 'react'; import { Col, Form, Row } from 'react-bootstrap'; +import { useHistory } from 'react-router-dom'; import { EditButton } from '@/components/common/EditButton'; import LoadingBackdrop from '@/components/common/LoadingBackdrop'; @@ -16,18 +17,17 @@ import AreaContainer from '@/components/measurements/AreaContainer'; import VolumeContainer from '@/components/measurements/VolumeContainer'; import * as API from '@/constants/API'; import { Claims, PropertyTenureTypes } from '@/constants/index'; +import { useQuery } from '@/hooks/use-query'; import useKeycloakWrapper from '@/hooks/useKeycloakWrapper'; import useLookupCodeHelpers from '@/hooks/useLookupCodeHelpers'; import { booleanToYesNoUnknownString, stringToBoolean } from '@/utils/formUtils'; import { getPrettyLatLng } from '@/utils/mapPropertyUtils'; -import { EditManagementState, PropertyEditForms } from '../../../PropertyViewSelector'; import { IPropertyDetailsForm, readOnlyMultiSelectStyle } from './PropertyDetailsTabView.helpers'; export interface IPropertyDetailsTabView { property?: IPropertyDetailsForm; loading: boolean; - setEditManagementState: (state: EditManagementState | null) => void; } /** @@ -37,7 +37,6 @@ export interface IPropertyDetailsTabView { export const PropertyDetailsTabView: React.FunctionComponent = ({ property, loading, - setEditManagementState, }) => { const { getOptionsByType } = useLookupCodeHelpers(); const { hasClaim } = useKeycloakWrapper(); @@ -52,6 +51,8 @@ export const PropertyDetailsTabView: React.FunctionComponent obj?.id === PropertyTenureTypes.HighwayRoad); @@ -67,10 +68,8 @@ export const PropertyDetailsTabView: React.FunctionComponent { - setEditManagementState({ - form: PropertyEditForms.UpdatePropertyDetailsContainer, - childId: null, - }); + query.set('edit', 'true'); + history.push({ search: query.toString() }); }} /> )} diff --git a/source/frontend/src/features/mapSideBar/property/tabs/propertyDetailsManagement/activity/detail/PropertyActivityDetailView.tsx b/source/frontend/src/features/mapSideBar/property/tabs/propertyDetailsManagement/activity/detail/PropertyActivityDetailView.tsx index fe96fb4dd9..250ead36a4 100644 --- a/source/frontend/src/features/mapSideBar/property/tabs/propertyDetailsManagement/activity/detail/PropertyActivityDetailView.tsx +++ b/source/frontend/src/features/mapSideBar/property/tabs/propertyDetailsManagement/activity/detail/PropertyActivityDetailView.tsx @@ -69,7 +69,7 @@ export const PropertyActivityDetailView: React.FunctionComponent< title="Edit property activity" onClick={() => { history.push( - `/mapview/sidebar/property/${props.propertyId}/activity/${props.activity?.id}/edit`, + `/mapview/sidebar/property/${props.propertyId}/management/activity/${props.activity?.id}/edit`, ); }} /> diff --git a/source/frontend/src/features/mapSideBar/property/tabs/propertyDetailsManagement/activity/edit/PropertyActivityEditContainer.tsx b/source/frontend/src/features/mapSideBar/property/tabs/propertyDetailsManagement/activity/edit/PropertyActivityEditContainer.tsx index cc6663cc0b..95288c2bbd 100644 --- a/source/frontend/src/features/mapSideBar/property/tabs/propertyDetailsManagement/activity/edit/PropertyActivityEditContainer.tsx +++ b/source/frontend/src/features/mapSideBar/property/tabs/propertyDetailsManagement/activity/edit/PropertyActivityEditContainer.tsx @@ -101,13 +101,15 @@ export const PropertyActivityEditContainer: React.FunctionComponent< if (result !== undefined) { setStaleLastUpdatedBy(true); - history.push(`/mapview/sidebar/property/${propertyId}/activity/${result.id}`); + history.push(`/mapview/sidebar/property/${propertyId}/management/activity/${result.id}`); } }; const onCancelClick = () => { if (propertyActivityId !== undefined) { - history.push(`/mapview/sidebar/property/${propertyId}/activity/${propertyActivityId}`); + history.push( + `/mapview/sidebar/property/${propertyId}/management/activity/${propertyActivityId}`, + ); } else { onClose(); } diff --git a/source/frontend/src/features/mapSideBar/property/tabs/propertyDetailsManagement/activity/list/ManagementActivitiesListContainer.tsx b/source/frontend/src/features/mapSideBar/property/tabs/propertyDetailsManagement/activity/list/ManagementActivitiesListContainer.tsx index b1ad408dbf..d1e5817574 100644 --- a/source/frontend/src/features/mapSideBar/property/tabs/propertyDetailsManagement/activity/list/ManagementActivitiesListContainer.tsx +++ b/source/frontend/src/features/mapSideBar/property/tabs/propertyDetailsManagement/activity/list/ManagementActivitiesListContainer.tsx @@ -51,11 +51,11 @@ const PropertyManagementActivitiesListContainer: React.FunctionComponent< //TODO: remove staleLastUpdatedBy when side bar context is refactored. const onCreate = () => { - history.push(`/mapview/sidebar/property/${propertyId}/activity/new`); + history.push(`/mapview/sidebar/property/${propertyId}/management/activity/new`); }; const onView = (activityId: number) => { - history.push(`/mapview/sidebar/property/${propertyId}/activity/${activityId}`); + history.push(`/mapview/sidebar/property/${propertyId}/management/activity/${activityId}`); }; return ( diff --git a/source/frontend/src/features/mapSideBar/property/tabs/propertyDetailsManagement/detail/PropertyContactListContainer.tsx b/source/frontend/src/features/mapSideBar/property/tabs/propertyDetailsManagement/detail/PropertyContactListContainer.tsx index a6d34a40a2..5a24f45bda 100644 --- a/source/frontend/src/features/mapSideBar/property/tabs/propertyDetailsManagement/detail/PropertyContactListContainer.tsx +++ b/source/frontend/src/features/mapSideBar/property/tabs/propertyDetailsManagement/detail/PropertyContactListContainer.tsx @@ -3,18 +3,16 @@ import { useCallback, useEffect, useState } from 'react'; import { usePropertyContactRepository } from '@/hooks/repositories/usePropertyContactRepository'; import { Api_PropertyContact } from '@/models/api/Property'; -import { EditManagementState } from '../../../PropertyViewSelector'; import { IPropertyContactListViewProps } from './PropertyContactListView'; interface IPropertyContactListContainerProps { propertyId: number; - setEditManagementState: (state: EditManagementState | null) => void; View: React.FC; } export const PropertyContactListContainer: React.FunctionComponent< IPropertyContactListContainerProps -> = ({ propertyId, setEditManagementState, View }) => { +> = ({ propertyId, View }) => { const [propertyContacts, setPropertyContacts] = useState([]); const { @@ -47,7 +45,6 @@ export const PropertyContactListContainer: React.FunctionComponent< ); diff --git a/source/frontend/src/features/mapSideBar/property/tabs/propertyDetailsManagement/detail/PropertyContactListView.test.tsx b/source/frontend/src/features/mapSideBar/property/tabs/propertyDetailsManagement/detail/PropertyContactListView.test.tsx index 8ee1a09111..c6e1ea1de5 100644 --- a/source/frontend/src/features/mapSideBar/property/tabs/propertyDetailsManagement/detail/PropertyContactListView.test.tsx +++ b/source/frontend/src/features/mapSideBar/property/tabs/propertyDetailsManagement/detail/PropertyContactListView.test.tsx @@ -29,7 +29,6 @@ describe('PropertyContactListView component', () => { , { diff --git a/source/frontend/src/features/mapSideBar/property/tabs/propertyDetailsManagement/detail/PropertyContactListView.tsx b/source/frontend/src/features/mapSideBar/property/tabs/propertyDetailsManagement/detail/PropertyContactListView.tsx index bfc87f8151..94dd0cce04 100644 --- a/source/frontend/src/features/mapSideBar/property/tabs/propertyDetailsManagement/detail/PropertyContactListView.tsx +++ b/source/frontend/src/features/mapSideBar/property/tabs/propertyDetailsManagement/detail/PropertyContactListView.tsx @@ -1,25 +1,28 @@ +import { generatePath, useHistory, useRouteMatch } from 'react-router-dom'; + import LoadingBackdrop from '@/components/common/LoadingBackdrop'; import { Section } from '@/components/common/Section/Section'; import { SectionListHeader } from '@/components/common/SectionListHeader'; import Claims from '@/constants/claims'; import { Api_PropertyContact } from '@/models/api/Property'; -import { EditManagementState, PropertyEditForms } from '../../../PropertyViewSelector'; +import { InventoryTabNames } from '../../../InventoryTabs'; +import { PropertyEditForms } from '../../../PropertyRouter'; import PropertyContactList from './PropertyContactList'; export interface IPropertyContactListViewProps { isLoading: boolean; propertyContacts: Api_PropertyContact[]; - setEditManagementState: (state: EditManagementState | null) => void; onDelete: (contactId: number) => void; } export const PropertyContactListView: React.FunctionComponent = ({ isLoading, propertyContacts, - setEditManagementState, onDelete, }) => { + const history = useHistory(); + const match = useRouteMatch<{ propertyId: string }>(); return (

- setEditManagementState({ - form: PropertyEditForms.UpdateContactContainer, - childId: null, - }) - } + onAdd={() => { + const path = generatePath(match.path, { + propertyId: match.params.propertyId, + tab: InventoryTabNames.management, + }); + history.push(`${path}/${PropertyEditForms.UpdateContactContainer}?edit=true`); + }} /> } > @@ -43,10 +47,13 @@ export const PropertyContactListView: React.FunctionComponent { - setEditManagementState({ - form: PropertyEditForms.UpdateContactContainer, - childId: contactId, + const path = generatePath(match.path, { + propertyId: match.params.propertyId, + tab: InventoryTabNames.management, }); + history.push( + `${path}/${PropertyEditForms.UpdateContactContainer}/${contactId}?edit=true`, + ); }} handleDelete={onDelete} /> diff --git a/source/frontend/src/features/mapSideBar/property/tabs/propertyDetailsManagement/detail/PropertyManagementTabView.tsx b/source/frontend/src/features/mapSideBar/property/tabs/propertyDetailsManagement/detail/PropertyManagementTabView.tsx index a1e2802e43..5e149da28f 100644 --- a/source/frontend/src/features/mapSideBar/property/tabs/propertyDetailsManagement/detail/PropertyManagementTabView.tsx +++ b/source/frontend/src/features/mapSideBar/property/tabs/propertyDetailsManagement/detail/PropertyManagementTabView.tsx @@ -4,7 +4,6 @@ import LoadingBackdrop from '@/components/common/LoadingBackdrop'; import { StyledSummarySection } from '@/components/common/Section/SectionStyles'; import { Api_Property } from '@/models/api/Property'; -import { EditManagementState } from '../../../PropertyViewSelector'; import PropertyManagementActivitiesListContainer from '../activity/list/ManagementActivitiesListContainer'; import ManagementActivitiesListView from '../activity/list/ManagementActivitiesListView'; import { PropertyContactListContainer } from './PropertyContactListContainer'; @@ -15,7 +14,6 @@ import { PropertyManagementDetailView } from './summary/PropertyManagementDetail export interface IPropertyManagementTabView { property: Api_Property; loading: boolean; - setEditManagementState: (state: EditManagementState | null) => void; } /** @@ -25,7 +23,6 @@ export interface IPropertyManagementTabView { export const PropertyManagementTabView: React.FunctionComponent = ({ property, loading, - setEditManagementState, }) => { if (property.id !== undefined) { return ( @@ -34,13 +31,8 @@ export const PropertyManagementTabView: React.FunctionComponent - + { return <>; }); - const setEditManagementState = jest.fn(); - const setup = ( renderOptions?: RenderOptions & { props?: Partial }, ) => { @@ -52,7 +50,6 @@ describe('PropertyManagementDetailContainer component', () => { , { diff --git a/source/frontend/src/features/mapSideBar/property/tabs/propertyDetailsManagement/detail/summary/PropertyManagementDetailContainer.tsx b/source/frontend/src/features/mapSideBar/property/tabs/propertyDetailsManagement/detail/summary/PropertyManagementDetailContainer.tsx index 6ca2f6093c..b9f3783d65 100644 --- a/source/frontend/src/features/mapSideBar/property/tabs/propertyDetailsManagement/detail/summary/PropertyManagementDetailContainer.tsx +++ b/source/frontend/src/features/mapSideBar/property/tabs/propertyDetailsManagement/detail/summary/PropertyManagementDetailContainer.tsx @@ -2,18 +2,16 @@ import { useCallback, useEffect } from 'react'; import { usePropertyManagementRepository } from '@/hooks/repositories/usePropertyManagementRepository'; -import { EditManagementState } from '../../../../PropertyViewSelector'; import { IPropertyManagementDetailViewProps } from './PropertyManagementDetailView'; export interface IPropertyManagementDetailContainerProps { propertyId: number; - setEditManagementState: (state: EditManagementState | null) => void; View: React.FC; } export const PropertyManagementDetailContainer: React.FunctionComponent< IPropertyManagementDetailContainerProps -> = ({ propertyId, setEditManagementState, View }) => { +> = ({ propertyId, View }) => { const { getPropertyManagement: { execute: getPropertyManagement, @@ -33,11 +31,5 @@ export const PropertyManagementDetailContainer: React.FunctionComponent< fetchPropertyManagement(); }, [fetchPropertyManagement]); - return ( - - ); + return ; }; diff --git a/source/frontend/src/features/mapSideBar/property/tabs/propertyDetailsManagement/detail/summary/PropertyManagementDetailView.test.tsx b/source/frontend/src/features/mapSideBar/property/tabs/propertyDetailsManagement/detail/summary/PropertyManagementDetailView.test.tsx index d76576b10b..ecdc3db993 100644 --- a/source/frontend/src/features/mapSideBar/property/tabs/propertyDetailsManagement/detail/summary/PropertyManagementDetailView.test.tsx +++ b/source/frontend/src/features/mapSideBar/property/tabs/propertyDetailsManagement/detail/summary/PropertyManagementDetailView.test.tsx @@ -1,5 +1,6 @@ +import { createMemoryHistory } from 'history'; + import { Claims } from '@/constants'; -import { PropertyEditForms } from '@/features/mapSideBar/property/PropertyViewSelector'; import { mockLookups } from '@/mocks/lookups.mock'; import { getMockApiPropertyManagement, @@ -20,7 +21,7 @@ const storeState = { [lookupCodesSlice.name]: { lookupCodes: mockLookups }, }; -const setEditManagementState = jest.fn(); +const history = createMemoryHistory(); describe('PropertyManagementDetailView component', () => { const setup = ( @@ -30,7 +31,6 @@ describe('PropertyManagementDetailView component', () => { const utils = render( { />, { ...renderOptions, + history: history, store: storeState, useMockAuthentication: true, }, @@ -97,9 +98,6 @@ describe('PropertyManagementDetailView component', () => { const { getByTitle } = setup({ claims: [Claims.MANAGEMENT_EDIT] }); const editButton = getByTitle('Edit property management information'); await act(async () => userEvent.click(editButton)); - expect(setEditManagementState).toHaveBeenCalledWith({ - form: PropertyEditForms.UpdateManagementSummaryContainer, - childId: null, - }); + expect(history.location.search).toBe('?edit=true'); }); }); diff --git a/source/frontend/src/features/mapSideBar/property/tabs/propertyDetailsManagement/detail/summary/PropertyManagementDetailView.tsx b/source/frontend/src/features/mapSideBar/property/tabs/propertyDetailsManagement/detail/summary/PropertyManagementDetailView.tsx index 23035678f4..fb3a8a2f1f 100644 --- a/source/frontend/src/features/mapSideBar/property/tabs/propertyDetailsManagement/detail/summary/PropertyManagementDetailView.tsx +++ b/source/frontend/src/features/mapSideBar/property/tabs/propertyDetailsManagement/detail/summary/PropertyManagementDetailView.tsx @@ -1,3 +1,5 @@ +import { useHistory } from 'react-router-dom'; + import { EditButton } from '@/components/common/EditButton'; import LoadingBackdrop from '@/components/common/LoadingBackdrop'; import { MultiselectTextList } from '@/components/common/MultiselectTextList'; @@ -5,10 +7,7 @@ import { Section } from '@/components/common/Section/Section'; import { SectionField } from '@/components/common/Section/SectionField'; import { StyledEditWrapper } from '@/components/common/Section/SectionStyles'; import { Claims } from '@/constants/index'; -import { - EditManagementState, - PropertyEditForms, -} from '@/features/mapSideBar/property/PropertyViewSelector'; +import { useQuery } from '@/hooks/use-query'; import useKeycloakWrapper from '@/hooks/useKeycloakWrapper'; import { Api_PropertyManagement } from '@/models/api/Property'; import { formatApiPropertyManagementLease } from '@/utils'; @@ -17,27 +16,25 @@ import { booleanToYesNoUnknownString } from '@/utils/formUtils'; export interface IPropertyManagementDetailViewProps { isLoading: boolean; propertyManagement: Api_PropertyManagement | null; - setEditManagementState: (state: EditManagementState | null) => void; } export const PropertyManagementDetailView: React.FC = ({ isLoading, propertyManagement, - setEditManagementState, }) => { const { hasClaim } = useKeycloakWrapper(); + const query = useQuery(); + const history = useHistory(); return (
- {setEditManagementState !== undefined && hasClaim(Claims.MANAGEMENT_EDIT) && ( + {hasClaim(Claims.MANAGEMENT_EDIT) && ( - setEditManagementState({ - form: PropertyEditForms.UpdateManagementSummaryContainer, - childId: null, - }) - } + onClick={() => { + query.set('edit', 'true'); + history.push({ search: query.toString() }); + }} /> )} diff --git a/source/frontend/src/features/mapSideBar/router/MapRouter.tsx b/source/frontend/src/features/mapSideBar/router/MapRouter.tsx index bebfe9ef3b..73a1ae1f42 100644 --- a/source/frontend/src/features/mapSideBar/router/MapRouter.tsx +++ b/source/frontend/src/features/mapSideBar/router/MapRouter.tsx @@ -176,12 +176,11 @@ export const MapRouter: React.FunctionComponent = memo(props => title={'Property Information'} /> ( - + )} claim={Claims.PROPERTY_VIEW} - exact key={'PropertyNonInventory'} title={'Property Information - Non Inventory'} /> diff --git a/source/frontend/src/features/mapSideBar/router/PropertyActivityRouter.tsx b/source/frontend/src/features/mapSideBar/router/PropertyActivityRouter.tsx index d5c48c9251..ebed802690 100644 --- a/source/frontend/src/features/mapSideBar/router/PropertyActivityRouter.tsx +++ b/source/frontend/src/features/mapSideBar/router/PropertyActivityRouter.tsx @@ -41,7 +41,7 @@ export const PropertyActivityRouter: React.FunctionComponent< return ( ( ( ( void; @@ -28,7 +25,6 @@ export interface IPropertyFileContainerProps { customTabs: TabInventoryView[]; defaultTab: InventoryTabNames; fileContext?: FileTypes; - withRouter?: boolean; } export const PropertyFileContainer: React.FunctionComponent< @@ -88,11 +84,6 @@ export const PropertyFileContainer: React.FunctionComponent< { - if (state?.form === PropertyEditForms.UpdatePropertyDetailsContainer) { - props.setEditFileProperty(); - } - }} /> ), key: InventoryTabNames.property, @@ -128,24 +119,9 @@ export const PropertyFileContainer: React.FunctionComponent< const InventoryTabsView = props.View; let activeTab: InventoryTabNames; - let setActiveTab: (tab: InventoryTabNames) => void; - // Use state-based tabs OR route-based tabs (as passed in the 'withRouter' property) - const [activeTabState, setActiveTabState] = useState(props.defaultTab); - const history = useHistory(); const params = useParams<{ tab?: string }>(); - - if (!!props.withRouter) { - activeTab = Object.values(InventoryTabNames).find(t => t === params.tab) ?? props.defaultTab; - setActiveTab = (tab: InventoryTabNames) => { - if (activeTab !== tab) { - history.push(`${tab}`); - } - }; - } else { - activeTab = activeTabState; - setActiveTab = setActiveTabState; - } + activeTab = Object.values(InventoryTabNames).find(t => t === params.tab) ?? props.defaultTab; return ( ); };