Skip to content

Commit

Permalink
Minor cleanup
Browse files Browse the repository at this point in the history
- remove some unneeded code
- move yup schema check to YupSchema.ts/yup.d.ts
- Move some Feature type checks to dedicated type guard functions
  • Loading branch information
NickPhura committed Jun 21, 2024
1 parent 89e6543 commit 855d829
Show file tree
Hide file tree
Showing 12 changed files with 191 additions and 189 deletions.
5 changes: 3 additions & 2 deletions app/src/components/map/components/ImportBoundaryDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,17 @@ import { Feature } from 'geojson';
import { boundaryUploadHelper } from 'utils/mapBoundaryUploadHelpers';

export interface IImportBoundaryDialogProps {
dialogTitle: string;
isOpen: boolean;
onClose: () => void;
onSuccess: (features: Feature[]) => void;
onFailure: (message: string) => void;
}

const ImportBoundaryDialog = (props: IImportBoundaryDialogProps) => {
const { isOpen, onClose, onSuccess, onFailure } = props;
const { dialogTitle, isOpen, onClose, onSuccess, onFailure } = props;

Check warning on line 17 in app/src/components/map/components/ImportBoundaryDialog.tsx

View check run for this annotation

Codecov / codecov/patch

app/src/components/map/components/ImportBoundaryDialog.tsx#L17

Added line #L17 was not covered by tests
return (
<ComponentDialog open={isOpen} dialogTitle="Import Boundary" onClose={onClose}>
<ComponentDialog open={isOpen} dialogTitle={dialogTitle} onClose={onClose}>
<Box>
<Box mb={3}>
<Alert severity="info">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import FormikErrorSnackbar from 'components/alert/FormikErrorSnackbar';
import HorizontalSplitFormComponent from 'components/fields/HorizontalSplitFormComponent';
import { Formik, FormikProps } from 'formik';
import { ICreateCaptureRequest, IEditCaptureRequest } from 'interfaces/useCritterApi.interface';
import { isDefined, isValidCoordinates } from 'utils/Utils';
import { isDefined } from 'utils/Utils';
import yup from 'utils/YupSchema';
import { MarkingsForm } from '../../../markings/MarkingsForm';
import { MeasurementsForm } from '../../../measurements/MeasurementsForm';
Expand Down Expand Up @@ -49,12 +49,7 @@ export const AnimalCaptureForm = <FormikValuesType extends ICreateCaptureRequest
.of(yup.number())
.min(2)
.max(3)
.test('is-valid-coordinates', 'Latitude or longitude values are outside of the valid range.', (value) => {
if (!value) {
return false;
}
return isValidCoordinates(value[1], value[0]);
})
.isValidPointCoordinates('Latitude or longitude values are outside of the valid range.')
.required('Latitude or longitude values are outside of the valid range.')
}),
properties: yup.object().optional()
Expand All @@ -63,13 +58,24 @@ export const AnimalCaptureForm = <FormikValuesType extends ICreateCaptureRequest
.default(undefined)
.required('Capture location is required'),
release_location: yup
.array(
yup.object({
geojson: yup.array().min(1, 'Release location is required if it is different from the capture location')
})
)
.min(1, 'Release location is required if it is different from the capture location')
.object()
.shape({
type: yup.string(),
// Points may have 3 coords for [lon, lat, elevation]
geometry: yup.object({
type: yup.string(),
coordinates: yup
.array()
.of(yup.number())
.min(2)
.max(3)
.isValidPointCoordinates('Latitude or longitude values are outside of the valid range.')
.required('Latitude or longitude values are outside of the valid range.')
}),
properties: yup.object().optional()
})
.nullable()
.default(undefined)
}),
measurements: yup.array(
yup
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,18 @@ import StaticLayers from 'components/map/components/StaticLayers';
import { MapBaseCss } from 'components/map/styles/MapBaseCss';
import { ALL_OF_BC_BOUNDARY, MAP_DEFAULT_CENTER, MAP_DEFAULT_ZOOM } from 'constants/spatial';
import LatitudeLongitudeTextFields from 'features/surveys/animals/profile/components/LatitudeLongitudeTextFields';
import { getIn, useFormikContext } from 'formik';
import { Feature } from 'geojson';
import { useFormikContext } from 'formik';
import { Feature, Point } from 'geojson';
import { ICreateCaptureRequest, IEditCaptureRequest } from 'interfaces/useCritterApi.interface';
import { DrawEvents, LatLngBoundsExpression } from 'leaflet';
import 'leaflet-fullscreen/dist/leaflet.fullscreen.css';
import 'leaflet-fullscreen/dist/Leaflet.fullscreen.js';
import 'leaflet/dist/leaflet.css';
import { debounce, get } from 'lodash-es';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useEffect, useMemo, useRef, useState } from 'react';
import { FeatureGroup, LayersControl, MapContainer as LeafletMapContainer } from 'react-leaflet';
import { calculateUpdatedMapBounds } from 'utils/mapBoundaryUploadHelpers';
import { getCoordinatesFromGeoJson, isValidCoordinates } from 'utils/Utils';
import { getCoordinatesFromGeoJson, isGeoJsonPointFeature, isValidCoordinates } from 'utils/spatial-utils';

export interface ICaptureLocationMapControlProps {
name: string;
Expand Down Expand Up @@ -56,22 +56,26 @@ export const CaptureLocationMapControl = <FormikValuesType extends ICreateCaptur
const { mapId } = props;

// Define location as a GeoJson object using useMemo to memoize the value
const captureLocationGeoJson: Feature | undefined = useMemo(() => {
const location: { latitude: number; longitude: number } | Feature = get(values, name);
const captureLocationGeoJson: Feature<Point> | undefined = useMemo(() => {
const location: { latitude: number; longitude: number } | Feature | undefined | null = get(values, name);

Check warning on line 60 in app/src/features/surveys/animals/profile/captures/capture-form/components/location/CaptureLocationMapControl.tsx

View check run for this annotation

Codecov / codecov/patch

app/src/features/surveys/animals/profile/captures/capture-form/components/location/CaptureLocationMapControl.tsx#L59-L60

Added lines #L59 - L60 were not covered by tests

if (!location) {
return;
}

if ('latitude' in location && isValidCoordinates(location.latitude, location.longitude)) {
if (
'latitude' in location &&
'longitude' in location &&
isValidCoordinates(location.latitude, location.longitude)
) {
return {
type: 'Feature',
geometry: { type: 'Point', coordinates: [location.longitude, location.latitude] },
properties: {}
};
}

if ('type' in location) {
if (isGeoJsonPointFeature(location)) {
return location;
}
}, [name, values]);
Expand All @@ -87,22 +91,23 @@ export const CaptureLocationMapControl = <FormikValuesType extends ICreateCaptur
// Update map bounds when the data changes
useEffect(() => {

Check warning on line 92 in app/src/features/surveys/animals/profile/captures/capture-form/components/location/CaptureLocationMapControl.tsx

View check run for this annotation

Codecov / codecov/patch

app/src/features/surveys/animals/profile/captures/capture-form/components/location/CaptureLocationMapControl.tsx#L92

Added line #L92 was not covered by tests
if (captureLocationGeoJson) {
if ('type' in captureLocationGeoJson) {
const coordinates = getCoordinatesFromGeoJson(captureLocationGeoJson);
if (isValidCoordinates(coordinates?.latitude, coordinates?.longitude)) {
setUpdatedBounds(calculateUpdatedMapBounds([captureLocationGeoJson]));
}
const { latitude, longitude } = getCoordinatesFromGeoJson(captureLocationGeoJson);

Check warning on line 94 in app/src/features/surveys/animals/profile/captures/capture-form/components/location/CaptureLocationMapControl.tsx

View check run for this annotation

Codecov / codecov/patch

app/src/features/surveys/animals/profile/captures/capture-form/components/location/CaptureLocationMapControl.tsx#L94

Added line #L94 was not covered by tests

if (isValidCoordinates(latitude, longitude)) {
setUpdatedBounds(calculateUpdatedMapBounds([captureLocationGeoJson]));

Check warning on line 97 in app/src/features/surveys/animals/profile/captures/capture-form/components/location/CaptureLocationMapControl.tsx

View check run for this annotation

Codecov / codecov/patch

app/src/features/surveys/animals/profile/captures/capture-form/components/location/CaptureLocationMapControl.tsx#L97

Added line #L97 was not covered by tests
}
} else {
// If the capture location is not a valid point, set the bounds to the entire province
setUpdatedBounds(calculateUpdatedMapBounds([ALL_OF_BC_BOUNDARY]));

Check warning on line 101 in app/src/features/surveys/animals/profile/captures/capture-form/components/location/CaptureLocationMapControl.tsx

View check run for this annotation

Codecov / codecov/patch

app/src/features/surveys/animals/profile/captures/capture-form/components/location/CaptureLocationMapControl.tsx#L101

Added line #L101 was not covered by tests
}
}, [captureLocationGeoJson]);

const updateFormikLocationFromLatLon = useCallback(
debounce((name, feature) => {
setFieldValue(name, feature);
}, 600),
[]
const updateFormikLocationFromLatLon = useMemo(

Check warning on line 105 in app/src/features/surveys/animals/profile/captures/capture-form/components/location/CaptureLocationMapControl.tsx

View check run for this annotation

Codecov / codecov/patch

app/src/features/surveys/animals/profile/captures/capture-form/components/location/CaptureLocationMapControl.tsx#L105

Added line #L105 was not covered by tests
() =>
debounce((name, feature) => {
setFieldValue(name, feature);

Check warning on line 108 in app/src/features/surveys/animals/profile/captures/capture-form/components/location/CaptureLocationMapControl.tsx

View check run for this annotation

Codecov / codecov/patch

app/src/features/surveys/animals/profile/captures/capture-form/components/location/CaptureLocationMapControl.tsx#L107-L108

Added lines #L107 - L108 were not covered by tests
}, 500),
[setFieldValue]
);

// Update formik and map when latitude/longitude text inputs change
Expand All @@ -115,7 +120,14 @@ export const CaptureLocationMapControl = <FormikValuesType extends ICreateCaptur
return;

Check warning on line 120 in app/src/features/surveys/animals/profile/captures/capture-form/components/location/CaptureLocationMapControl.tsx

View check run for this annotation

Codecov / codecov/patch

app/src/features/surveys/animals/profile/captures/capture-form/components/location/CaptureLocationMapControl.tsx#L119-L120

Added lines #L119 - L120 were not covered by tests
}

const feature: Feature = {
// If coordinates are invalid, reset the map to show nothing
if (!isValidCoordinates(lat, lon)) {
drawControlsRef.current?.clearLayers();
setUpdatedBounds(calculateUpdatedMapBounds([ALL_OF_BC_BOUNDARY]));
return;

Check warning on line 127 in app/src/features/surveys/animals/profile/captures/capture-form/components/location/CaptureLocationMapControl.tsx

View check run for this annotation

Codecov / codecov/patch

app/src/features/surveys/animals/profile/captures/capture-form/components/location/CaptureLocationMapControl.tsx#L125-L127

Added lines #L125 - L127 were not covered by tests
}

const feature: Feature<Point> = {

Check warning on line 130 in app/src/features/surveys/animals/profile/captures/capture-form/components/location/CaptureLocationMapControl.tsx

View check run for this annotation

Codecov / codecov/patch

app/src/features/surveys/animals/profile/captures/capture-form/components/location/CaptureLocationMapControl.tsx#L130

Added line #L130 was not covered by tests
id: 1,
type: 'Feature',
geometry: {
Expand All @@ -127,49 +139,29 @@ export const CaptureLocationMapControl = <FormikValuesType extends ICreateCaptur

// Update formik through debounce function
updateFormikLocationFromLatLon(name, feature);

Check warning on line 141 in app/src/features/surveys/animals/profile/captures/capture-form/components/location/CaptureLocationMapControl.tsx

View check run for this annotation

Codecov / codecov/patch

app/src/features/surveys/animals/profile/captures/capture-form/components/location/CaptureLocationMapControl.tsx#L141

Added line #L141 was not covered by tests

// If coordinates are invalid, reset the map to show nothing
if (!isValidCoordinates(lat, lon)) {
drawControlsRef.current?.clearLayers();
setLastDrawn(1);
setUpdatedBounds(calculateUpdatedMapBounds([ALL_OF_BC_BOUNDARY]));
return;
}

// Remove any existing drawn items in the edit layer
drawControlsRef.current?.clearLayers();
setLastDrawn(null);
}, [latitudeInput, longitudeInput]);
}, [latitudeInput, longitudeInput, name, setFieldValue, updateFormikLocationFromLatLon]);

return (
<Grid item xs={12}>
{typeof get(errors, name) == 'string' && !Array.isArray(get(errors, name)) && (
{typeof get(errors, name) === 'string' && !Array.isArray(get(errors, name)) && (
<Alert severity="error" variant="outlined" sx={{ mb: 2 }}>
<AlertTitle>Missing capture location</AlertTitle>
{get(errors, name)}
</Alert>
)}

{getIn(errors, `${name}.geometry.coordinates`) && (
<Alert severity="error" variant="outlined" sx={{ mb: 2 }}>
<AlertTitle>Invalid coordinates</AlertTitle>
{getIn(errors, `${name}.geometry.coordinates`)}
</Alert>
)}

<Box component="fieldset">
<Paper variant="outlined">
<ImportBoundaryDialog
dialogTitle={`Import ${title}`}
isOpen={isOpen}
onClose={() => setIsOpen(false)}
onSuccess={(features) => {
setUpdatedBounds(calculateUpdatedMapBounds(features));
setFieldValue(name, features[0]);
setFieldError(name, undefined);
// Unset last drawn to show staticlayers, where the file geometry is loaded to
lastDrawn && drawControlsRef?.current?.deleteLayer(lastDrawn);
drawControlsRef?.current?.addLayer(features[0], () => 1);
setLastDrawn(1);
if ('coordinates' in features[0].geometry) {
setLatitudeInput(String(features[0].geometry.coordinates[1]));
setLongitudeInput(String(features[0].geometry.coordinates[0]));

Check warning on line 167 in app/src/features/surveys/animals/profile/captures/capture-form/components/location/CaptureLocationMapControl.tsx

View check run for this annotation

Codecov / codecov/patch

app/src/features/surveys/animals/profile/captures/capture-form/components/location/CaptureLocationMapControl.tsx#L166-L167

Added lines #L166 - L167 were not covered by tests
Expand Down Expand Up @@ -198,18 +190,10 @@ export const CaptureLocationMapControl = <FormikValuesType extends ICreateCaptur
latitudeValue={latitudeInput}
longitudeValue={longitudeInput}
onLatitudeChange={(event) => {
if (event.currentTarget.value) {
setLatitudeInput(event.currentTarget.value);
} else {
setLatitudeInput('');
}
setLatitudeInput(event.currentTarget.value ?? '');
}}
onLongitudeChange={(event) => {
if (event.currentTarget.value) {
setLongitudeInput(event.currentTarget.value);
} else {
setLongitudeInput('');
}
setLongitudeInput(event.currentTarget.value ?? '');
}}
/>
<Box display="flex">
Expand Down Expand Up @@ -253,16 +237,18 @@ export const CaptureLocationMapControl = <FormikValuesType extends ICreateCaptur
if (lastDrawn) {
drawControlsRef?.current?.deleteLayer(lastDrawn);
}
setFieldError(name, undefined);

const feature: Feature = event.layer.toGeoJSON();

Check warning on line 241 in app/src/features/surveys/animals/profile/captures/capture-form/components/location/CaptureLocationMapControl.tsx

View check run for this annotation

Codecov / codecov/patch

app/src/features/surveys/animals/profile/captures/capture-form/components/location/CaptureLocationMapControl.tsx#L241

Added line #L241 was not covered by tests

setFieldError(name, undefined);

Check warning on line 243 in app/src/features/surveys/animals/profile/captures/capture-form/components/location/CaptureLocationMapControl.tsx

View check run for this annotation

Codecov / codecov/patch

app/src/features/surveys/animals/profile/captures/capture-form/components/location/CaptureLocationMapControl.tsx#L243

Added line #L243 was not covered by tests
setFieldValue(name, feature);
// Set last drawn to remove it if a subsequent shape is added. There can only be one shape.
setLastDrawn(id);
// Update the text box lat/lon inputs

if ('coordinates' in feature.geometry) {
setLatitudeInput(String(feature.geometry.coordinates[1]));
setLongitudeInput(String(feature.geometry.coordinates[0]));

Check warning on line 248 in app/src/features/surveys/animals/profile/captures/capture-form/components/location/CaptureLocationMapControl.tsx

View check run for this annotation

Codecov / codecov/patch

app/src/features/surveys/animals/profile/captures/capture-form/components/location/CaptureLocationMapControl.tsx#L247-L248

Added lines #L247 - L248 were not covered by tests
}

setLastDrawn(id);
}}
onLayerEdit={(event: DrawEvents.Edited) => {
event.layers.getLayers().forEach((layer: any) => {
Expand All @@ -282,16 +268,14 @@ export const CaptureLocationMapControl = <FormikValuesType extends ICreateCaptur
</FeatureGroup>

<LayersControl position="bottomright">
{!lastDrawn && (
<StaticLayers
layers={[
{
layerName: 'Capture Location',
features: get(values, name) ? [{ geoJSON: get(values, name), key: Math.random() }] : []
}
]}
/>
)}
<StaticLayers
layers={[
{
layerName: `${title}`,
features: get(values, name) ? [{ geoJSON: get(values, name), key: Math.random() }] : []
}
]}
/>
<BaseLayerControls />
</LayersControl>
</LeafletMapContainer>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { MarkingsForm } from 'features/surveys/animals/profile/markings/Markings
import { MeasurementsForm } from 'features/surveys/animals/profile/measurements/MeasurementsForm';
import { Formik, FormikProps } from 'formik';
import { ICreateMortalityRequest, IEditMortalityRequest } from 'interfaces/useCritterApi.interface';
import { isDefined, isValidCoordinates } from 'utils/Utils';
import { isDefined } from 'utils/Utils';
import yup from 'utils/YupSchema';
import { CauseOfDeathForm } from './cause-of-death/CauseOfDeathForm';
import { MortalityGeneralInformationForm } from './general-information/MortalityGeneralInformationForm';
Expand Down Expand Up @@ -47,12 +47,7 @@ export const AnimalMortalityForm = <FormikValuesType extends ICreateMortalityReq
.of(yup.number())
.min(2)
.max(3)
.test('is-valid-coordinates', 'Latitude or longitude values are outside of the valid range.', (value) => {
if (!value) {
return false;
}
return isValidCoordinates(value[1], value[0]);
})
.isValidPointCoordinates('Latitude or longitude values are outside of the valid range.')
.required('Latitude or longitude values are outside of the valid range.')
}),
properties: yup.object().optional()
Expand Down
Loading

0 comments on commit 855d829

Please sign in to comment.