From f5b7b9267f516d22ffada7f98050ac36168c60d5 Mon Sep 17 00:00:00 2001 From: Maximilian Harz Date: Fri, 31 Jan 2025 10:38:54 +0100 Subject: [PATCH 01/29] Try to type Item and getValue (WIP) --- src/Components/Map/Layer.tsx | 7 +------ src/Utils/GetValue.ts | 13 ++++++++----- src/types/Item.d.ts | 3 +-- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/Components/Map/Layer.tsx b/src/Components/Map/Layer.tsx index 7aeadf30..07be04fe 100644 --- a/src/Components/Map/Layer.tsx +++ b/src/Components/Map/Layer.tsx @@ -1,11 +1,6 @@ /* eslint-disable @typescript-eslint/restrict-plus-operands */ -/* eslint-disable @typescript-eslint/no-unsafe-call */ -/* eslint-disable @typescript-eslint/no-unsafe-return */ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-unnecessary-condition */ -/* eslint-disable @typescript-eslint/no-unsafe-argument */ /* eslint-disable @typescript-eslint/prefer-optional-chain */ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ import { Children, isValidElement, useEffect, useState } from 'react' import { Marker, Tooltip } from 'react-leaflet' @@ -319,7 +314,7 @@ export const Layer = ({ )} - {item.name ? item.name : getValue(item, itemNameField)} + {item.name ? item.name : `${getValue(item, itemNameField)}`} ) diff --git a/src/Utils/GetValue.ts b/src/Utils/GetValue.ts index ff159599..2d8500fe 100644 --- a/src/Utils/GetValue.ts +++ b/src/Utils/GetValue.ts @@ -1,14 +1,17 @@ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ -/* eslint-disable @typescript-eslint/no-unsafe-return */ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -export function getValue(obj, path) { +import type { Item } from '#types/Item' + +function getNestedValue(obj: Object, path: string) { + re +} + +export function getValue(obj: Item | undefined, path: string): Item | string | undefined { if (!obj || typeof path !== 'string') return undefined const pathArray = path.split('.') // Use a different variable for the split path for (let i = 0, len = pathArray.length; i < len; i++) { if (!obj) return undefined // Check if obj is falsy at each step // eslint-disable-next-line security/detect-object-injection - obj = obj[pathArray[i]] // Dive one level deeper + obj = obj[pathArray[i]] as Item // Dive one level deeper } return obj // Return the final value } diff --git a/src/types/Item.d.ts b/src/types/Item.d.ts index 47560e66..cb8da0be 100644 --- a/src/types/Item.d.ts +++ b/src/types/Item.d.ts @@ -24,8 +24,7 @@ export interface Item { slug?: string user_created?: UserItem image?: string - // eslint-disable-next-line @typescript-eslint/no-explicit-any - [key: string]: any + group_type: string /* constructor( id: string, name: string, From 4316387ecb0e597b0d046a4ba0ac9674f1a6cb60 Mon Sep 17 00:00:00 2001 From: Maximilian Harz Date: Fri, 31 Jan 2025 23:29:32 +0100 Subject: [PATCH 02/29] Improve typing of items, remove getValue --- src/Components/Map/Layer.tsx | 73 +++++-------------- .../Subcomponents/Controls/SearchControl.tsx | 3 - .../ItemPopupComponents/HeaderView.tsx | 27 ++----- .../ItemPopupComponents/PopupButton.tsx | 7 +- .../ItemPopupComponents/TextView.tsx | 33 ++++----- .../Map/Subcomponents/ItemViewPopup.tsx | 2 +- src/Components/Map/UtopiaMapInner.tsx | 7 +- .../Map/hooks/useSelectPosition.tsx | 2 +- src/Components/Map/hooks/useTags.tsx | 28 +++---- src/Components/Profile/ProfileForm.tsx | 25 +++---- src/Components/Profile/ProfileView.tsx | 35 ++++----- .../Profile/Subcomponents/ActionsButton.tsx | 7 +- .../Profile/Subcomponents/ContactInfoView.tsx | 2 +- .../Subcomponents/LinkedItemsHeaderView.tsx | 25 +------ .../Profile/Subcomponents/ProfileTextForm.tsx | 5 +- .../Profile/Subcomponents/ProfileTextView.tsx | 6 +- src/Components/Profile/Templates/FlexForm.tsx | 2 - src/Components/Profile/Templates/FlexView.tsx | 22 +++--- .../Profile/Templates/OnepagerView.tsx | 5 +- .../Profile/Templates/SimpleView.tsx | 2 +- src/Components/Profile/Templates/TabsForm.tsx | 3 +- src/Components/Profile/Templates/TabsView.tsx | 7 +- src/Components/Templates/ItemCard.tsx | 16 +--- src/Components/Templates/MarketView.tsx | 26 +++---- .../Templates/OverlayItemsIndexPage.tsx | 3 - src/Utils/GetValue.ts | 17 ----- src/types/FormState.d.ts | 2 + src/types/Item.d.ts | 22 +++++- src/types/ItemType.d.ts | 12 ++- src/types/LayerProps.d.ts | 19 ++--- 30 files changed, 166 insertions(+), 279 deletions(-) delete mode 100644 src/Utils/GetValue.ts diff --git a/src/Components/Map/Layer.tsx b/src/Components/Map/Layer.tsx index 07be04fe..373df1dc 100644 --- a/src/Components/Map/Layer.tsx +++ b/src/Components/Map/Layer.tsx @@ -1,11 +1,9 @@ -/* eslint-disable @typescript-eslint/restrict-plus-operands */ /* eslint-disable @typescript-eslint/no-unnecessary-condition */ /* eslint-disable @typescript-eslint/prefer-optional-chain */ import { Children, isValidElement, useEffect, useState } from 'react' import { Marker, Tooltip } from 'react-leaflet' import { encodeTag } from '#utils/FormatTags' -import { getValue } from '#utils/GetValue' import { hashTagRegex } from '#utils/HashTagRegex' import MarkerIconFactory from '#utils/MarkerIconFactory' import { randomColor } from '#utils/RandomColor' @@ -42,17 +40,6 @@ export const Layer = ({ markerDefaultColor2 = 'RGBA(35, 31, 32, 0.2)', api, itemType, - itemNameField = 'name', - itemSubnameField, - itemTextField = 'text', - itemAvatarField, - itemColorField, - itemOwnerField, - itemLatitudeField = 'position.coordinates.1', - itemLongitudeField = 'position.coordinates.0', - itemTagsField, - itemOffersField, - itemNeedsField, onlyOnePerOwner = false, customEditLink, customEditParameter, @@ -105,16 +92,8 @@ export const Layer = ({ markerDefaultColor2, api, itemType, - itemNameField, - itemSubnameField, - itemTextField, - itemAvatarField, - itemColorField, - itemOwnerField, - itemTagsField, - itemOffersField, - itemNeedsField, onlyOnePerOwner, + // Can we just use editCallback for all cases? customEditLink, customEditParameter, // eslint-disable-next-line camelcase @@ -122,6 +101,7 @@ export const Layer = ({ listed, setItemFormPopup, itemFormPopup, + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment clusterRef, }) api && @@ -138,15 +118,6 @@ export const Layer = ({ markerDefaultColor2, api, itemType, - itemNameField, - itemSubnameField, - itemTextField, - itemAvatarField, - itemColorField, - itemOwnerField, - itemTagsField, - itemOffersField, - itemNeedsField, onlyOnePerOwner, customEditLink, customEditParameter, @@ -155,6 +126,7 @@ export const Layer = ({ listed, setItemFormPopup, itemFormPopup, + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment clusterRef, }) // eslint-disable-next-line react-hooks/exhaustive-deps @@ -196,29 +168,19 @@ export const Layer = ({ visibleGroupTypes.length === 0, ) .map((item: Item) => { - if (getValue(item, itemLongitudeField) && getValue(item, itemLatitudeField)) { - // eslint-disable-next-line security/detect-object-injection - if (getValue(item, itemTextField)) item[itemTextField] = getValue(item, itemTextField) - // eslint-disable-next-line security/detect-object-injection - else item[itemTextField] = '' - + if (item.position?.coordinates[0] && item.position?.coordinates[1]) { if (item.tags) { - // eslint-disable-next-line security/detect-object-injection - item[itemTextField] = item[itemTextField] + '\n\n' + item.text += '\n\n' item.tags.map((tag) => { - // eslint-disable-next-line security/detect-object-injection - if (!item[itemTextField].includes(`#${encodeTag(tag)}`)) { - // eslint-disable-next-line security/detect-object-injection - return (item[itemTextField] = item[itemTextField] + `#${encodeTag(tag)} `) + if (!item.text.includes(`#${encodeTag(tag)}`)) { + item.text += `#${encodeTag(tag)}` } - // eslint-disable-next-line security/detect-object-injection - return item[itemTextField] + return item.text }) } if (allTagsLoaded && allItemsLoaded) { - // eslint-disable-next-line security/detect-object-injection - item[itemTextField].match(hashTagRegex)?.map((tag) => { + item.text.match(hashTagRegex)?.map((tag) => { if ( !tags.find( (t) => t.name.toLocaleLowerCase() === tag.slice(1).toLocaleLowerCase(), @@ -241,19 +203,18 @@ export const Layer = ({ const itemTags = getItemTags(item) - const latitude = - itemLatitudeField && item ? getValue(item, itemLatitudeField) : undefined - const longitude = - itemLongitudeField && item ? getValue(item, itemLongitudeField) : undefined + const latitude = item.position.coordinates[1] + const longitude = item.position.coordinates[0] let color1 = markerDefaultColor let color2 = markerDefaultColor2 - if (itemColorField && getValue(item, itemColorField) != null) - color1 = getValue(item, itemColorField) - else if (itemTags && itemTags[0]) { + if (item.color) { + color1 = item.color + } else if (itemTags && itemTags[0]) { color1 = itemTags[0].color } - if (itemTags && itemTags[0] && itemColorField) color2 = itemTags[0].color + // What is happening here?? Why do we depend on itemColorField? + if (itemTags && itemTags[0] && item.layer?.hasColor) color2 = itemTags[0].color else if (itemTags && itemTags[1]) { color2 = itemTags[1].color } @@ -314,7 +275,7 @@ export const Layer = ({ )} - {item.name ? item.name : `${getValue(item, itemNameField)}`} + {item.name} ) diff --git a/src/Components/Map/Subcomponents/Controls/SearchControl.tsx b/src/Components/Map/Subcomponents/Controls/SearchControl.tsx index 323d8c5c..68aaf51e 100644 --- a/src/Components/Map/Subcomponents/Controls/SearchControl.tsx +++ b/src/Components/Map/Subcomponents/Controls/SearchControl.tsx @@ -23,7 +23,6 @@ import { useLeafletRefs } from '#components/Map/hooks/useLeafletRefs' import { useTags } from '#components/Map/hooks/useTags' import useWindowDimensions from '#components/Map/hooks/useWindowDimension' import { decodeTag } from '#utils/FormatTags' -import { getValue } from '#utils/GetValue' import MarkerIconFactory from '#utils/MarkerIconFactory' import { LocateControl } from './LocateControl' @@ -73,8 +72,6 @@ export const SearchControl = () => { searchGeo() setItemsResults( items.filter((item) => { - if (item.layer?.itemNameField) item.name = getValue(item, item.layer.itemNameField) - if (item.layer?.itemTextField) item.text = getValue(item, item.layer.itemTextField) return ( value.length > 2 && ((item.layer?.listed && item.name.toLowerCase().includes(value.toLowerCase())) || diff --git a/src/Components/Map/Subcomponents/ItemPopupComponents/HeaderView.tsx b/src/Components/Map/Subcomponents/ItemPopupComponents/HeaderView.tsx index b7602afc..7e694963 100644 --- a/src/Components/Map/Subcomponents/ItemPopupComponents/HeaderView.tsx +++ b/src/Components/Map/Subcomponents/ItemPopupComponents/HeaderView.tsx @@ -15,7 +15,6 @@ import { useNavigate } from 'react-router-dom' import { useAppState } from '#components/AppShell/hooks/useAppState' import { useHasUserPermission } from '#components/Map/hooks/usePermissions' import DialogModal from '#components/Templates/DialogModal' -import { getValue } from '#utils/GetValue' import type { Item } from '#types/Item' import type { ItemsApi } from '#types/ItemsApi' @@ -26,9 +25,6 @@ export function HeaderView({ editCallback, deleteCallback, setPositionCallback, - itemNameField, - itemSubnameField, - itemAvatarField, loading, hideMenu = false, big = false, @@ -64,22 +60,11 @@ export function HeaderView({ }, [item]) const avatar = - itemAvatarField && getValue(item, itemAvatarField) - ? appState.assetsApi.url + - getValue(item, itemAvatarField) + - `${big ? '?width=160&heigth=160' : '?width=80&heigth=80'}` - : item.layer?.itemAvatarField && - item && - getValue(item, item.layer?.itemAvatarField) && - appState.assetsApi.url + - getValue(item, item.layer?.itemAvatarField) + - `${big ? '?width=160&heigth=160' : '?width=80&heigth=80'}` - const title = itemNameField - ? getValue(item, itemNameField) - : item.layer?.itemNameField && item && getValue(item, item.layer.itemNameField) - const subtitle = itemSubnameField - ? getValue(item, itemSubnameField) - : item.layer?.itemSubnameField && item && getValue(item, item.layer.itemSubnameField) + appState.assetsApi.url + + item.avatar + + `${big ? '?width=160&heigth=160' : '?width=80&heigth=80'}` + const title = item.name + const subtitle = item.subname const [address] = useState('') @@ -168,7 +153,7 @@ export function HeaderView({ onClick={(e) => item.layer?.customEditLink ? navigate( - `${item.layer.customEditLink}${item.layer.customEditParameter ? `/${getValue(item, item.layer.customEditParameter)}${params && '?' + params}` : ''} `, + `${item.layer.customEditLink}${item.layer.customEditParameter ? `/${item.id}${params && '?' + params}` : ''} `, ) : editCallback(e) } diff --git a/src/Components/Map/Subcomponents/ItemPopupComponents/PopupButton.tsx b/src/Components/Map/Subcomponents/ItemPopupComponents/PopupButton.tsx index e417cd8a..d1d1c80d 100644 --- a/src/Components/Map/Subcomponents/ItemPopupComponents/PopupButton.tsx +++ b/src/Components/Map/Subcomponents/ItemPopupComponents/PopupButton.tsx @@ -3,7 +3,6 @@ import { Link } from 'react-router-dom' import { useGetItemTags } from '#components/Map/hooks/useTags' -import { getValue } from '#utils/GetValue' import type { Item } from '#types/Item' @@ -11,23 +10,21 @@ export const PopupButton = ({ url, parameterField, text, - colorField, item, }: { url: string parameterField?: string text: string - colorField?: string item?: Item }) => { const params = new URLSearchParams(window.location.search) const getItemTags = useGetItemTags() return ( - +