react-mapfilter
Version:
These components are designed for viewing data in Mapeo. They share a common interface:
166 lines (149 loc) • 6.37 kB
JavaScript
import "core-js/modules/es.array.iterator";
import "core-js/modules/web.dom-collections.iterator";
import _findInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/find";
import _filterInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/filter";
import _Object$assign from "@babel/runtime-corejs3/core-js-stable/object/assign";
import _objectWithoutPropertiesLoose from "@babel/runtime-corejs3/helpers/objectWithoutPropertiesLoose";
import _sliceInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/slice";
import _mapInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/map";
import _Array$isArray from "@babel/runtime-corejs3/core-js-stable/array/is-array";
// @flow
import * as React from 'react';
import isEqual from 'lodash/isEqual';
import createFilterOrig from 'mapeo-entity-filter';
import ObservationDialog from './ObservationDialog';
import getStats from './stats';
import { defaultGetPreset } from './utils/helpers';
/*:: import type { Observation } from 'mapeo-schema'*/
/*:: import type {
PresetWithFields,
PresetWithAdditionalFields,
GetMedia,
Filter,
GetIconUrl,
GetMediaUrl
} from './types'*/
/*:: export type CommonViewProps = {
/** Array of observations to render *-/
observations?: Array<Observation>,
/** Called when an observation is editing/updated *-/
onUpdateObservation: (observation: Observation) => void,
onDeleteObservation: (id: string) => void,
/** A function called with an observation that should return a matching preset
* with field definitions *-/
presets?: PresetWithFields[],
getMediaUrl: GetMediaUrl,
getIconUrl?: GetIconUrl,
/** Filter to apply to observations *-/
filter?: Filter
}*/
/*:: type Props = {
...$Exact<CommonViewProps>,
children: ({
filteredObservations: Array<Observation>,
onClickObservation: (observationId: string, imageIndex?: number) => void,
getPreset: Observation => PresetWithAdditionalFields,
getMedia: GetMedia
}) => React.Node
}*/
const noop = () => {}; // This is a temporary wrapper to compile a filter that defines $preset into a
// filter that will work with our dataset, which currently uses categoryId to
// define which preset applies. We will need to improve how this works in the
// future once we start matching presets like we do with iD
const createFilter = (filter
/*: Filter | void*/
) => {
if (!_Array$isArray(filter) || filter[0] !== 'all' || filter.length < 2) {
return () => true;
}
const presetFilter = _mapInstanceProperty(filter).call(filter, subFilter => {
if (!_Array$isArray(subFilter) || subFilter[1] !== '$preset' && !isEqual(subFilter[1], ['$preset'])) {
return subFilter;
}
return [subFilter[0], 'categoryId', ..._sliceInstanceProperty(subFilter).call(subFilter, 2)];
});
return createFilterOrig(presetFilter);
};
const WrappedMapView = (_ref) => {
let {
observations = [],
onUpdateObservation = noop,
onDeleteObservation = noop,
presets = [],
getMediaUrl,
filter,
children
}
/*: Props*/
= _ref,
otherProps = _objectWithoutPropertiesLoose(_ref, ["observations", "onUpdateObservation", "onDeleteObservation", "presets", "getMediaUrl", "filter", "children"]);
const stats = React.useMemo(() => getStats(observations), [observations]);
const [editingObservation, setEditingObservation] = React.useState(null);
const [editingInitialImageIndex, setEditingInitialImageIndex] = React.useState();
const getPresetWithFallback = React.useCallback((observation
/*: Observation*/
) =>
/*: PresetWithAdditionalFields*/
{
var _context;
const preset = getPreset(observation, presets);
const defaultPreset = defaultGetPreset(observation, stats);
if (!preset) return defaultPreset;
return _Object$assign({}, preset, {
additionalFields: _filterInstanceProperty(_context = defaultPreset.additionalFields).call(_context, // Any fields that are not defined in the preset we show as 'additionalFields'
additionalField => {
var _context2;
return !_findInstanceProperty(_context2 = preset.fields).call(_context2, field => {
const fieldKey = _Array$isArray(field.key) ? field.key : [field.key];
const additionalFieldKey = _Array$isArray(additionalField.key) ? additionalField.key : [additionalField.key];
return isEqual(fieldKey, additionalFieldKey);
});
})
});
}, [presets, stats]);
const handleObservationClick = React.useCallback((observationId, imageIndex) => {
setEditingInitialImageIndex(imageIndex);
setEditingObservation(_findInstanceProperty(observations).call(observations, obs => obs.id === observationId));
}, [observations]);
const getMedia = React.useCallback((attachment, {
width = 800
} = {}) => {
const dpr = window.devicePixelRatio;
const size = width < 300 * dpr ? 'thumbnail' : width < 1200 * dpr ? 'preview' : 'original';
return {
src: getMediaUrl(attachment.id, size),
type: 'image'
};
}, [getMediaUrl]);
const filterFunction = React.useMemo(() => createFilter(filter), [filter]);
const filteredObservations = React.useMemo(() => filter ? _filterInstanceProperty(observations).call(observations, filterFunction) : observations, [observations, filterFunction, filter]);
return /*#__PURE__*/React.createElement(React.Fragment, null, children({
onClickObservation: handleObservationClick,
filteredObservations,
getPreset: getPresetWithFallback,
getMedia
}), /*#__PURE__*/React.createElement(ObservationDialog, {
open: !!editingObservation,
observation: editingObservation,
initialImageIndex: editingInitialImageIndex,
getPreset: getPresetWithFallback,
getMedia: getMedia,
onRequestClose: () => setEditingObservation(false),
onSave: onUpdateObservation,
onDelete: onDeleteObservation
}));
};
export default WrappedMapView; // TODO: Update this function to match presets like ID Editor
function getPreset(observation
/*: Observation*/
, presets
/*: PresetWithFields[]*/
)
/*: PresetWithFields | void*/
{
const tags = observation.tags;
if (!tags || !tags.categoryId) return;
const preset = _findInstanceProperty(presets).call(presets, preset => preset.id === tags.categoryId);
return preset;
}
//# sourceMappingURL=ViewWrapper.js.map