-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: Map and Label breaking on back action #3825
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -45,11 +45,11 @@ interface MapAndLabelContextValue { | |
type MapAndLabelProviderProps = PropsWithChildren<PresentationalProps>; | ||
|
||
const MapAndLabelContext = createContext<MapAndLabelContextValue | undefined>( | ||
undefined, | ||
undefined | ||
); | ||
|
||
export const MapAndLabelProvider: React.FC<MapAndLabelProviderProps> = ( | ||
props, | ||
props | ||
) => { | ||
const { schema, children, handleSubmit, previouslySubmittedData, fn } = props; | ||
const { formikConfig, initialValues } = useSchema({ | ||
|
@@ -62,7 +62,7 @@ export const MapAndLabelProvider: React.FC<MapAndLabelProviderProps> = ( | |
fn | ||
] as FeatureCollection; | ||
const previousFormData = previousGeojson?.features.map( | ||
(feature) => feature.properties, | ||
(feature) => feature.properties | ||
) as SchemaUserResponse[]; | ||
const _previousMapData = previousGeojson?.features; | ||
|
||
|
@@ -83,6 +83,7 @@ export const MapAndLabelProvider: React.FC<MapAndLabelProviderProps> = ( | |
const mergedProperties = { | ||
...feature.properties, | ||
...values.schemaData[i], | ||
label: `${i + 1}`, | ||
}; | ||
feature["properties"] = mergedProperties; | ||
geojson.features.push(feature); | ||
|
@@ -99,11 +100,13 @@ export const MapAndLabelProvider: React.FC<MapAndLabelProviderProps> = ( | |
}); | ||
|
||
const [activeIndex, setActiveIndex] = useState<number>( | ||
previousFormData?.length - 1 || -1, | ||
previousFormData ? previousFormData?.length - 1 : 0 | ||
); | ||
|
||
const [minError, setMinError] = useState<boolean>(false); | ||
const [maxError, setMaxError] = useState<boolean>(false); | ||
const [loadPreviousValuesOnMap, setLoadPreviousValuesOnMap] = | ||
useState<boolean>(Boolean(previouslySubmittedData)); | ||
|
||
const handleGeoJSONChange = (event: GeoJSONChangeEvent) => { | ||
// If the user clicks 'reset' on the map, geojson will be empty object | ||
|
@@ -147,7 +150,9 @@ export const MapAndLabelProvider: React.FC<MapAndLabelProviderProps> = ( | |
formik.setErrors({}); | ||
}; | ||
|
||
const removeAllFeaturesFromMap = () => setFeatures(undefined); | ||
const removeAllFeaturesFromMap = () => { | ||
setFeatures(undefined); | ||
}; | ||
|
||
const removeAllFeaturesFromForm = () => { | ||
formik.setFieldValue("schemaData", []); | ||
|
@@ -179,8 +184,11 @@ export const MapAndLabelProvider: React.FC<MapAndLabelProviderProps> = ( | |
setActiveIndex(newFeatures.length - 1); | ||
}; | ||
|
||
const addInitialFeaturesToMap = (features: Feature[]) => { | ||
setFeatures(features); | ||
const addInitialFeaturesToMap = (initialFeatures: Feature[]) => { | ||
if (loadPreviousValuesOnMap) { | ||
setFeatures(initialFeatures); | ||
setLoadPreviousValuesOnMap(false); | ||
} | ||
}; | ||
|
||
const addFeatureToForm = () => { | ||
|
@@ -198,21 +206,24 @@ export const MapAndLabelProvider: React.FC<MapAndLabelProviderProps> = ( | |
|
||
const copyFeature = (sourceIndex: number, destinationIndex: number) => { | ||
const sourceFeature = formik.values.schemaData[sourceIndex]; | ||
formik.setFieldValue(`schemaData[${destinationIndex}]`, sourceFeature); | ||
formik.setFieldValue(`schemaData[${destinationIndex}]`, { | ||
...sourceFeature, | ||
label: `${destinationIndex + 1}`, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The label was being assigned based on the object you were copying from rather than the object we were copying to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch but I don't think this is quite working in all scenarios correctly yet! For example:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks so much for catching this, I'll add some adjustments There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Testing added for this and hope I have solved it. I couldn't find another bug through manual testing... |
||
}); | ||
}; | ||
|
||
const removeFeatureFromForm = (index: number) => { | ||
formik.setFieldValue( | ||
"schemaData", | ||
formik.values.schemaData.filter((_, i) => i !== index), | ||
formik.values.schemaData.filter((_, i) => i !== index) | ||
); | ||
}; | ||
|
||
const removeFeatureFromMap = (index: number) => { | ||
// Order of features can vary by change/modification, filter on label not array position | ||
const label = `${index + 1}`; | ||
const filteredFeatures = features?.filter( | ||
(f) => f.properties?.label !== label, | ||
(f) => f.properties?.label !== label | ||
); | ||
|
||
// Shift any feature labels that are larger than the removed feature label so they remain incremental | ||
|
@@ -236,7 +247,6 @@ export const MapAndLabelProvider: React.FC<MapAndLabelProviderProps> = ( | |
// Set active index as highest tab after removal, so that when you "add" a new feature the tabs increment correctly | ||
setActiveIndex((features && features.length - 2) || 0); | ||
}; | ||
|
||
return ( | ||
<MapAndLabelContext.Provider | ||
value={{ | ||
|
@@ -267,7 +277,7 @@ export const useMapAndLabelContext = (): MapAndLabelContextValue => { | |
const context = useContext(MapAndLabelContext); | ||
if (!context) { | ||
throw new Error( | ||
"useMapAndLabelContext must be used within a MapAndLabelProvider", | ||
"useMapAndLabelContext must be used within a MapAndLabelProvider" | ||
); | ||
} | ||
return context; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,13 @@ | ||
import { FeatureCollection } from "geojson"; | ||
|
||
import { mockTreeData } from "./GenericValues"; | ||
export type MockPayload = { data: { MockFn: FeatureCollection } }; | ||
export interface MockPayload { | ||
data: { MockFn: FeatureCollection }; | ||
} | ||
|
||
interface PreviousData extends MockPayload { | ||
auto: boolean; | ||
} | ||
|
||
export const mockSingleFeaturePayload: MockPayload = { | ||
data: { | ||
|
@@ -11,11 +18,47 @@ export const mockSingleFeaturePayload: MockPayload = { | |
coordinates: [-3.685929607119201, 57.15301433687542], | ||
type: "Point", | ||
}, | ||
properties: { mockTreeData }, | ||
properties: { mockTreeData, label: "1" }, | ||
type: "Feature", | ||
}, | ||
], | ||
type: "FeatureCollection", | ||
}, | ||
}, | ||
}; | ||
|
||
export const mockDoubleFeaturePayload: MockPayload = { | ||
data: { | ||
MockFn: { | ||
features: [ | ||
{ | ||
geometry: { | ||
coordinates: [-3.685929607119201, 57.15301433687542], | ||
type: "Point", | ||
}, | ||
properties: { mockTreeData, label: "1" }, | ||
type: "Feature", | ||
}, | ||
{ | ||
type: "Feature", | ||
properties: { ...mockTreeData, label: "2" }, | ||
geometry: { | ||
type: "Point", | ||
coordinates: [-3.686529607119201, 57.15310433687542], | ||
}, | ||
}, | ||
], | ||
type: "FeatureCollection", | ||
}, | ||
}, | ||
}; | ||
|
||
export const previouslySubmittedSingleFeature: PreviousData = { | ||
auto: false, | ||
...mockSingleFeaturePayload, | ||
}; | ||
|
||
export const previouslySubmittedDoubleFeature: PreviousData = { | ||
auto: false, | ||
...mockDoubleFeaturePayload, | ||
}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Per your question in the PR description, mocking |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
import { MyMap } from "@opensystemslab/map"; | ||
import React from "react"; | ||
import { setup } from "testUtils"; | ||
import { it, vi } from "vitest"; | ||
|
||
import { Presentational as MapAndLabel } from "../Public"; | ||
import { point1, point2, point3 } from "./mocks/geojson"; | ||
import { | ||
previouslySubmittedDoubleFeatureProps, | ||
previouslySubmittedSingleFeatureProps, | ||
} from "./mocks/Trees"; | ||
import { addMultipleFeatures, clickContinue } from "./utils"; | ||
|
||
beforeAll(() => { | ||
if (!window.customElements.get("my-map")) { | ||
window.customElements.define("my-map", MyMap); | ||
} | ||
|
||
const ResizeObserverMock = vi.fn(() => ({ | ||
observe: vi.fn(), | ||
unobserve: vi.fn(), | ||
disconnect: vi.fn(), | ||
})); | ||
|
||
vi.stubGlobal("ResizeObserver", ResizeObserverMock); | ||
jessicamcinchak marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}); | ||
|
||
describe("navigating back after adding single feature", () => { | ||
it("shows previously submitted features", async () => { | ||
const { getByTestId, queryByRole } = setup( | ||
<MapAndLabel {...previouslySubmittedSingleFeatureProps} /> | ||
); | ||
const map = getByTestId("map-and-label-map"); | ||
|
||
expect(map).toBeInTheDocument(); | ||
|
||
const firstTab = queryByRole("tab", { name: /Tree 1/ }); | ||
expect(firstTab).toBeVisible(); | ||
|
||
const firstTabPanel = getByTestId("vertical-tabpanel-0"); | ||
expect(firstTabPanel).toBeVisible(); | ||
|
||
// To properly add the features to the map, you need to pass all previous features as well | ||
addMultipleFeatures([point1, point2]); | ||
|
||
const secondTab = queryByRole("tab", { name: /Tree 2/ }); | ||
expect(secondTab).toBeVisible(); | ||
|
||
const secondTabPanel = getByTestId("vertical-tabpanel-1"); | ||
expect(secondTabPanel).toBeVisible(); | ||
}); | ||
}); | ||
|
||
describe("navigating back after adding two features", () => { | ||
it("shows previously submitted features", async () => { | ||
const { getByTestId, queryByRole } = setup( | ||
<MapAndLabel {...previouslySubmittedDoubleFeatureProps} /> | ||
); | ||
const map = getByTestId("map-and-label-map"); | ||
|
||
expect(map).toBeInTheDocument(); | ||
|
||
const firstTab = queryByRole("tab", { name: /Tree 1/ }); | ||
const secondTab = queryByRole("tab", { name: /Tree 2/ }); | ||
expect(firstTab).toBeInTheDocument(); | ||
expect(secondTab).toBeInTheDocument(); | ||
|
||
const secondTabPanel = getByTestId("vertical-tabpanel-1"); | ||
expect(secondTabPanel).toBeVisible(); | ||
|
||
// To properly add the features to the map, you need to pass all previous features as well | ||
addMultipleFeatures([point1, point2, point3]); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: aren't There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is correct, it should just be adding one feature at a time. I'll adjust and switch the functions There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Found that this was correct and just adding a single point deletes the others from the map, so I need them added like this. I've added a comment above each line explaining this need |
||
|
||
const thirdTab = queryByRole("tab", { name: /Tree 3/ }); | ||
expect(thirdTab).toBeVisible(); | ||
|
||
const thirdTabPanel = getByTestId("vertical-tabpanel-2"); | ||
expect(thirdTabPanel).toBeVisible(); | ||
}); | ||
it("should maintain labelling when removing a feature", async () => { | ||
const handleSubmit = vi.fn(); | ||
const { getByRole, user } = setup( | ||
<MapAndLabel | ||
{...previouslySubmittedDoubleFeatureProps} | ||
handleSubmit={handleSubmit} | ||
/> | ||
); | ||
|
||
const firstTab = getByRole("tab", { name: /Tree 1/ }); | ||
|
||
await user.click(firstTab); | ||
|
||
const removeButton = getByRole("button", { name: /remove/i }); | ||
|
||
await user.click(removeButton); | ||
|
||
await clickContinue(user); | ||
|
||
const output = | ||
handleSubmit.mock.calls[0][0].data.MockFn.features[0].properties.label; | ||
|
||
expect(output).toEqual("1"); | ||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, see above comment - not following this change in particular !