diff --git a/src/components/FeaturePanel/EditDialog/EditContent/FeatureEditSection/FeatureEditSection.tsx b/src/components/FeaturePanel/EditDialog/EditContent/FeatureEditSection/FeatureEditSection.tsx index 00bf0eb9..4632d1de 100644 --- a/src/components/FeaturePanel/EditDialog/EditContent/FeatureEditSection/FeatureEditSection.tsx +++ b/src/components/FeaturePanel/EditDialog/EditContent/FeatureEditSection/FeatureEditSection.tsx @@ -2,16 +2,46 @@ import { PresetSelect } from './PresetSelect'; import { MajorKeysEditor } from './MajorKeysEditor'; import { TagsEditor } from './TagsEditor/TagsEditor'; import React from 'react'; -import { SingleFeatureEditContextProvider } from './SingleFeatureEditContext'; +import { + SingleFeatureEditContextProvider, + useFeatureEditData, +} from './SingleFeatureEditContext'; import { MembersEditor } from '../MembersEditor'; import { ParentsEditor } from '../ParentsEditor'; +import { Stack, Typography } from '@mui/material'; +import { useEditContext } from '../../EditContext'; type Props = { shortId: string; }; +const EditFeatureHeading = (props: { shortId: string }) => { + const { items } = useEditContext(); + const { tags } = useFeatureEditData(); + + if (items.length <= 1) { + return null; + } + + return ( + + {tags.name || ' '} + + {props.shortId} + + + ); +}; + export const FeatureEditSection = ({ shortId }: Props) => ( + diff --git a/src/components/FeaturePanel/EditDialog/EditContent/MembersEditor.tsx b/src/components/FeaturePanel/EditDialog/EditContent/MembersEditor.tsx index ae44b251..210848fc 100644 --- a/src/components/FeaturePanel/EditDialog/EditContent/MembersEditor.tsx +++ b/src/components/FeaturePanel/EditDialog/EditContent/MembersEditor.tsx @@ -11,31 +11,16 @@ import { } from '@mui/material'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import { FeatureRow } from './FeatureRow'; -import { OsmId } from '../../../../services/types'; -import { getApiId, getShortId } from '../../../../services/helpers'; -import { fetchSchemaTranslations } from '../../../../services/tagging/translations'; -import { fetchFeature } from '../../../../services/osmApi'; -import { useEditContext } from '../EditContext'; import { t } from '../../../../services/intl'; +import { useGetHandleClick } from './helpers'; export const MembersEditor = () => { const { members } = useFeatureEditData(); const theme = useTheme(); - const { addFeature, items, setCurrent } = useEditContext(); + const handleClick = useGetHandleClick(); if (!members || members.length === 0) return null; - const handleClick = async (shortId) => { - const apiId: OsmId = getApiId(shortId); - await fetchSchemaTranslations(); - const isNotInItems = !items.find((item) => item.shortId === shortId); - const feature = await fetchFeature(apiId); - if (isNotInItems) { - addFeature(feature); - } - setCurrent(getShortId(feature.osmMeta)); - }; - return ( { const { shortId } = useFeatureEditData(); const [parents, setParents] = useState([]); const theme = useTheme(); - const { addFeature, setCurrent, items } = useEditContext(); + const handleClick = useGetHandleClick(); useEffect(() => { (async () => { @@ -65,16 +64,7 @@ export const ParentsEditor = () => { key={shortId} shortId={shortId} label={parent.tags.name} - onClick={() => { - const isNotInItems = !items.find( - (item) => item.shortId === shortId, - ); - fetchSchemaTranslations(); - if (isNotInItems) { - addFeature(parent); - } - setCurrent(shortId); - }} + onClick={() => handleClick(shortId)} /> ); })} diff --git a/src/components/FeaturePanel/EditDialog/EditContent/helpers.tsx b/src/components/FeaturePanel/EditDialog/EditContent/helpers.tsx index 507b0dbd..2d94150b 100644 --- a/src/components/FeaturePanel/EditDialog/EditContent/helpers.tsx +++ b/src/components/FeaturePanel/EditDialog/EditContent/helpers.tsx @@ -1,6 +1,10 @@ import styled from '@emotion/styled'; import { Box, Stack } from '@mui/material'; import React from 'react'; +import { EditDataItem } from '../useEditItems'; +import { useEditContext } from '../EditContext'; +import { getApiId, getShortId } from '../../../../services/helpers'; +import { getFullFeatureWithMemberFeatures } from '../../../../services/osmApi'; const CharacterCountContainer = styled.div` position: absolute; @@ -49,3 +53,27 @@ export const getInputTypeForKey = (key: string) => { } return 'text'; }; + +const isInItems = (items: Array, shortId: string) => + items.find((item) => item.shortId === shortId); + +export const useGetHandleClick = () => { + const { addFeature, items, setCurrent } = useEditContext(); + + return async (shortId: string) => { + const apiId = getApiId(shortId); + if (apiId.id < 0) { + setCurrent(shortId); + return; + } + + if (isInItems(items, shortId)) { + setCurrent(shortId); + return; + } + + const feature = await getFullFeatureWithMemberFeatures(apiId); + addFeature(feature); + setCurrent(getShortId(feature.osmMeta)); + }; +}; diff --git a/src/services/osmApi.ts b/src/services/osmApi.ts index 9d285537..accd8a61 100644 --- a/src/services/osmApi.ts +++ b/src/services/osmApi.ts @@ -1,7 +1,14 @@ import { resolveCountryCode } from 'next-codegrid'; import { FetchError, getShortId, getUrlOsmId, prod } from './helpers'; import { fetchJson } from './fetch'; -import { Feature, LonLat, OsmId, Position, SuccessInfo } from './types'; +import { + Feature, + LonLat, + OsmId, + Position, + RelationMember, + SuccessInfo, +} from './types'; import { removeFetchCache } from './fetchCache'; import { overpassAroundToSkeletons } from './overpassAroundToSkeletons'; import { isBrowser } from '../components/helpers'; @@ -20,30 +27,31 @@ import { } from '../utils'; import { getOverpassUrl } from './overpassSearch'; -type GetOsmUrl = (object: OsmId) => string; - -const getOsmUrl: GetOsmUrl = ({ type, id }) => +const getOsmUrl = ({ type, id }: OsmId) => `https://api.openstreetmap.org/api/0.6/${type}/${id}.json`; -const getOsmFullUrl: GetOsmUrl = ({ type, id }) => +const getOsmFullUrl = ({ type, id }: OsmId) => `https://api.openstreetmap.org/api/0.6/${type}/${id}/full.json`; -const getOsmParentUrl: GetOsmUrl = ({ type, id }) => +const getOsmParentUrl = ({ type, id }: OsmId) => `https://api.openstreetmap.org/api/0.6/${type}/${id}/relations.json`; -const getOsmHistoryUrl: GetOsmUrl = ({ type, id }) => +const getOsmHistoryUrl = ({ type, id }: OsmId) => `https://api.openstreetmap.org/api/0.6/${type}/${id}/history.json`; +type OsmTypes = 'node' | 'way' | 'relation'; +type OsmElement = { + type: T; + id: number; + lat: number; + lon: number; + timestamp: string; + version: number; + changeset: number; + user: string; + uid: number; + tags: Record; + members?: RelationMember[]; +}; type OsmResponse = { - elements?: { - type: 'node' | 'way' | 'relation'; - id: number; - lat: number; - lon: number; - timestamp: string; - version: number; - changeset: number; - user: string; - uid: number; - tags: Record; - }[]; + elements: OsmElement[]; }; const getOsmElement = async (apiId: OsmId) => { @@ -196,8 +204,12 @@ export const fetchParentFeatures = async (apiId: OsmId) => { return elements.map((element) => addSchemaToFeature(osmToFeature(element))); }; -const getItemsMap = (elements) => { - const map = { node: {}, way: {}, relation: {} }; +const getItemsMap = (elements: OsmElement[]) => { + const map = { + node: {} as Record>, + way: {} as Record>, + relation: {} as Record>, + }; elements.forEach((element) => { map[element.type][element.id] = element; }); @@ -270,6 +282,17 @@ const addMemberFeaturesToArea = async (relation: Feature) => { return { ...relation, memberFeatures }; }; +export const getFullFeatureWithMemberFeatures = async (apiId: OsmId) => { + await fetchSchemaTranslations(); + const full = await fetchJson(getOsmFullUrl(apiId)); + const map = getItemsMap(full.elements); + const feature = addSchemaToFeature(osmToFeature(map[apiId.type][apiId.id])); + return { + ...feature, + memberFeatures: getMemberFeatures(feature.members, map), + }; +}; + const addMemberFeaturesToRelation = async (relation: Feature) => { const { tags, osmMeta: apiId } = relation; if (apiId.type !== 'relation') { @@ -280,12 +303,10 @@ const addMemberFeaturesToRelation = async (relation: Feature) => { return await addMemberFeaturesToArea(relation); } - const full = await fetchJson(getOsmFullUrl(apiId)); - const map = getItemsMap(full.elements); - + const full = await getFullFeatureWithMemberFeatures(apiId); const out: Feature = { ...relation, - memberFeatures: getMemberFeatures(relation.members, map), + memberFeatures: full.memberFeatures, }; mergeMemberImageDefs(out); return out; diff --git a/src/services/types.ts b/src/services/types.ts index 6695fcb3..a5d1f852 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -72,7 +72,7 @@ export type FeatureTags = { [key: string]: string; }; -type RelationMember = { +export type RelationMember = { type: OsmType; ref: number; role: string;