diff --git a/src/Components/Map/UtopiaMap.css b/src/Components/Map/UtopiaMap.css
index 5ab6dc05..a1f1a014 100644
--- a/src/Components/Map/UtopiaMap.css
+++ b/src/Components/Map/UtopiaMap.css
@@ -134,6 +134,27 @@
left: 4px;
width: 24px;
}
+
+ .shop-icon {
+ position: relative;
+ top: -34px;
+ left: 4px;
+ width: 24px;
+ }
+
+ .plant-icon {
+ position: relative;
+ top: -34px;
+ left: 4px;
+ width: 24px;
+ }
+
+ .circle-dot-icon {
+ position: relative;
+ top: -36px;
+ left: 4px;
+ width: 24px;
+ }
.leaflet-popup-scrolled {
overflow-x: hidden;
diff --git a/src/Components/Map/UtopiaMap.tsx b/src/Components/Map/UtopiaMap.tsx
index 5240d681..757bca74 100644
--- a/src/Components/Map/UtopiaMap.tsx
+++ b/src/Components/Map/UtopiaMap.tsx
@@ -1,16 +1,46 @@
+import { LatLng } from 'leaflet'
+import { MapContainer } from 'react-leaflet'
+
import { ContextWrapper } from '#components/AppShell/ContextWrapper'
import { UtopiaMapInner } from './UtopiaMapInner'
import type { UtopiaMapProps } from '#types/UtopiaMapProps'
-
-// eslint-disable-next-line import/no-unassigned-import
import 'react-toastify/dist/ReactToastify.css'
-function UtopiaMap(props: UtopiaMapProps) {
+function UtopiaMap({
+ height = '500px',
+ width = '100%',
+ center = [50.6, 9.5],
+ zoom = 10,
+ children,
+ geo,
+ showFilterControl = false,
+ showGratitudeControl = false,
+ showLayerControl = true,
+ infoText,
+ donationWidget,
+}: UtopiaMapProps) {
return (
-
+
+
+ {children}
+
+
)
}
diff --git a/src/Components/Map/UtopiaMapInner.tsx b/src/Components/Map/UtopiaMapInner.tsx
index 3a8df9ce..58bb2b86 100644
--- a/src/Components/Map/UtopiaMapInner.tsx
+++ b/src/Components/Map/UtopiaMapInner.tsx
@@ -6,29 +6,20 @@
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-argument */
-import { LatLng } from 'leaflet'
-import {
- Children,
- cloneElement,
- createRef,
- isValidElement,
- useEffect,
- useRef,
- useState,
-} from 'react'
-import { TileLayer, MapContainer, useMapEvents, GeoJSON } from 'react-leaflet'
-// eslint-disable-next-line import/no-unassigned-import
+import { Children, cloneElement, isValidElement, useEffect, useRef, useState } from 'react'
+import { TileLayer, useMapEvents, GeoJSON, useMap } from 'react-leaflet'
import 'leaflet/dist/leaflet.css'
import MarkerClusterGroup from 'react-leaflet-cluster'
-import { Outlet } from 'react-router-dom'
+import { Outlet, useLocation } from 'react-router-dom'
import { toast } from 'react-toastify'
-
-// eslint-disable-next-line import/no-unassigned-import
import './UtopiaMap.css'
+import { containsUUID } from '#utils/ContainsUUID'
+
import { useClusterRef, useSetClusterRef } from './hooks/useClusterRef'
import { useAddVisibleLayer } from './hooks/useFilter'
import { useLayers } from './hooks/useLayers'
+import { useLeafletRefs } from './hooks/useLeafletRefs'
import {
useSelectPosition,
useSetMapClicked,
@@ -41,6 +32,7 @@ import { GratitudeControl } from './Subcomponents/Controls/GratitudeControl'
import { LayerControl } from './Subcomponents/Controls/LayerControl'
import { SearchControl } from './Subcomponents/Controls/SearchControl'
import { TagsControl } from './Subcomponents/Controls/TagsControl'
+import { PopupButton } from './Subcomponents/ItemPopupComponents/PopupButton'
import { TextView } from './Subcomponents/ItemPopupComponents/TextView'
import { SelectPosition } from './Subcomponents/SelectPosition'
@@ -48,21 +40,14 @@ import type { ItemFormPopupProps } from '#types/ItemFormPopupProps'
import type { UtopiaMapProps } from '#types/UtopiaMapProps'
import type { Feature, Geometry as GeoJSONGeometry } from 'geojson'
-const mapDivRef = createRef()
-
export function UtopiaMapInner({
- height = '500px',
- width = '100%',
- center = [50.6, 9.5],
- zoom = 10,
children,
geo,
showFilterControl = false,
showGratitudeControl = false,
showLayerControl = true,
- infoText,
+ donationWidget,
}: UtopiaMapProps) {
- // Hooks that rely on contexts, called after ContextWrapper is provided
const selectNewItemPosition = useSelectPosition()
const setSelectNewItemPosition = useSetSelectPosition()
const setClusterRef = useSetClusterRef()
@@ -72,6 +57,10 @@ export function UtopiaMapInner({
const layers = useLayers()
const addVisibleLayer = useAddVisibleLayer()
+ const leafletRefs = useLeafletRefs()
+
+ const location = useLocation()
+ const map = useMap()
useEffect(() => {
layers.forEach((layer) => addVisibleLayer(layer))
@@ -81,10 +70,22 @@ export function UtopiaMapInner({
const init = useRef(false)
useEffect(() => {
if (!init.current) {
- infoText &&
+ donationWidget &&
setTimeout(() => {
- toast(
, { autoClose: false })
- }, 4000)
+ toast(
+ <>
+
+
+ >,
+ { autoClose: false },
+ )
+ }, 600000)
init.current = true
}
// eslint-disable-next-line react-hooks/exhaustive-deps
@@ -105,9 +106,61 @@ export function UtopiaMapInner({
return null
}
+ useMapEvents({
+ popupopen: (e) => {
+ const item = Object.entries(leafletRefs).find((r) => r[1].popup === e.popup)?.[1].item
+ if (window.location.pathname.split('/')[1] !== item?.id) {
+ const params = new URLSearchParams(window.location.search)
+ if (!location.pathname.includes('/item/')) {
+ window.history.pushState(
+ {},
+ '',
+ `/${item?.id}` + `${params.toString() !== '' ? `?${params}` : ''}`,
+ )
+ }
+ let title = ''
+ if (item?.name) title = item.name
+ document.title = `${document.title.split('-')[0]} - ${title}`
+ }
+ },
+ })
+
+ const openPopup = () => {
+ if (!containsUUID(window.location.pathname)) {
+ map.closePopup()
+ } else {
+ if (window.location.pathname.split('/')[1]) {
+ const id = window.location.pathname.split('/')[1]
+ // eslint-disable-next-line security/detect-object-injection
+ const ref = leafletRefs[id]
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
+ if (ref) {
+ clusterRef.hasLayer(ref.marker) &&
+ clusterRef?.zoomToShowLayer(ref.marker, () => {
+ ref.marker.openPopup()
+ })
+ let title = ''
+ if (ref.item.name) title = ref.item.name
+ document.title = `${document.title.split('-')[0]} - ${title}`
+ document
+ .querySelector('meta[property="og:title"]')
+ ?.setAttribute('content', ref.item.name)
+ document
+ .querySelector('meta[property="og:description"]')
+ ?.setAttribute('content', ref.item.text ?? '')
+ }
+ }
+ }
+ }
+
+ useEffect(() => {
+ openPopup()
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [leafletRefs, location])
+
const resetMetaTags = () => {
const params = new URLSearchParams(window.location.search)
- if (!window.location.pathname.includes('/item/')) {
+ if (!containsUUID(window.location.pathname)) {
window.history.pushState({}, '', '/' + `${params.toString() !== '' ? `?${params}` : ''}`)
}
document.title = document.title.split('-')[0]
@@ -130,62 +183,53 @@ export function UtopiaMapInner({
-
+
+
+
+
+
+ {showFilterControl && }
+ {showLayerControl && }
+ {showGratitudeControl && }
+
+
+
setClusterRef(r as any)}
+ showCoverageOnHover
+ chunkedLoading
+ maxClusterRadius={50}
+ removeOutsideVisibleBounds={false}
>
-
-
-
-
-
-
- {showFilterControl && }
- {showLayerControl && }
- {showGratitudeControl && }
-
-
- setClusterRef(r)}
- showCoverageOnHover
- chunkedLoading
- maxClusterRadius={50}
- removeOutsideVisibleBounds={false}
- >
- {Children.toArray(children).map((child) =>
- isValidElement<{
- setItemFormPopup: React.Dispatch>
- itemFormPopup: ItemFormPopupProps | null
- clusterRef: React.MutableRefObject
- }>(child)
- ? cloneElement(child, { setItemFormPopup, itemFormPopup, clusterRef })
- : child,
- )}
-
- {geo && (
- {
- if (selectNewItemPosition) {
- e.layer.closePopup()
- setMapClicked({ position: e.latlng, setItemFormPopup })
- }
- },
- }}
- />
+ {Children.toArray(children).map((child) =>
+ isValidElement<{
+ setItemFormPopup: React.Dispatch>
+ itemFormPopup: ItemFormPopupProps | null
+ clusterRef: React.MutableRefObject
+ }>(child)
+ ? cloneElement(child, { setItemFormPopup, itemFormPopup, clusterRef })
+ : child,
)}
-
-
+
+ {geo && (
+
{
+ if (selectNewItemPosition) {
+ e.layer.closePopup()
+ setMapClicked({ position: e.latlng, setItemFormPopup })
+ }
+ },
+ }}
+ />
+ )}
+
{selectNewItemPosition != null && (
diff --git a/src/Components/Map/hooks/useItems.tsx b/src/Components/Map/hooks/useItems.tsx
index db174e77..bf8779fe 100644
--- a/src/Components/Map/hooks/useItems.tsx
+++ b/src/Components/Map/hooks/useItems.tsx
@@ -3,7 +3,7 @@
/* eslint-disable @typescript-eslint/no-empty-function */
/* eslint-disable @typescript-eslint/no-non-null-assertion */
/* eslint-disable @typescript-eslint/restrict-template-expressions */
-/* eslint-disable @typescript-eslint/no-unsafe-assignment */
+
/* eslint-disable @typescript-eslint/no-misused-promises */
import { useCallback, useReducer, createContext, useContext, useState } from 'react'
import { toast } from 'react-toastify'
@@ -82,6 +82,7 @@ function useItemsManager(initialItems: Item[]): {
},
})
result.map((item) => {
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
dispatch({ type: 'ADD', item: { ...item, layer } })
return null
})
diff --git a/src/Components/Map/hooks/useSelectPosition.tsx b/src/Components/Map/hooks/useSelectPosition.tsx
index 541e05a4..e53e0193 100644
--- a/src/Components/Map/hooks/useSelectPosition.tsx
+++ b/src/Components/Map/hooks/useSelectPosition.tsx
@@ -63,7 +63,7 @@ function useSelectPositionManager(): {
if ('menuIcon' in selectPosition) {
mapClicked &&
mapClicked.setItemFormPopup({
- layer: selectPosition as LayerProps,
+ layer: selectPosition,
position: mapClicked.position,
})
setSelectPosition(null)
@@ -98,6 +98,7 @@ function useSelectPositionManager(): {
success = true
// eslint-disable-next-line no-catch-all/no-catch-all
} catch (error) {
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
toast.error(error.toString())
}
if (success) {
@@ -123,6 +124,7 @@ function useSelectPositionManager(): {
success = true
// eslint-disable-next-line no-catch-all/no-catch-all
} catch (error) {
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
toast.error(error.toString())
}
if (success) {
@@ -145,6 +147,7 @@ function useSelectPositionManager(): {
success = true
// eslint-disable-next-line no-catch-all/no-catch-all
} catch (error) {
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
toast.error(error.toString())
}
if (success) {
diff --git a/src/Components/Map/hooks/useTags.tsx b/src/Components/Map/hooks/useTags.tsx
index f80e96ad..4649b627 100644
--- a/src/Components/Map/hooks/useTags.tsx
+++ b/src/Components/Map/hooks/useTags.tsx
@@ -5,12 +5,8 @@
/* eslint-disable @typescript-eslint/prefer-optional-chain */
/* eslint-disable @typescript-eslint/no-non-null-assertion */
/* eslint-disable @typescript-eslint/no-unnecessary-condition */
-/* eslint-disable @typescript-eslint/no-unsafe-assignment */
-/* eslint-disable @typescript-eslint/no-unsafe-call */
-/* eslint-disable @typescript-eslint/no-unsafe-member-access */
import { useCallback, useReducer, createContext, useContext, useState } from 'react'
-import { getValue } from '#utils/GetValue'
import { hashTagRegex } from '#utils/HashTagRegex'
import type { Item } from '#types/Item'
@@ -96,8 +92,7 @@ function useTagsManager(initialTags: Tag[]): {
const getItemTags = useCallback(
(item: Item) => {
- const text =
- item.layer?.itemTextField && item ? getValue(item, item.layer.itemTextField) : undefined
+ const text = item.text
const itemTagStrings = text?.match(hashTagRegex)
const itemTags: Tag[] = []
itemTagStrings?.map((tag) => {
@@ -108,18 +103,15 @@ function useTagsManager(initialTags: Tag[]): {
}
return null
})
- item.layer?.itemOffersField &&
- getValue(item, item.layer.itemOffersField)?.map((o) => {
- const offer = tags.find((t) => t.id === o.tags_id)
- offer && itemTags.push(offer)
- return null
- })
- item.layer?.itemNeedsField &&
- getValue(item, item.layer.itemNeedsField)?.map((n) => {
- const need = tags.find((t) => t.id === n.tags_id)
- need && itemTags.push(need)
- return null
- })
+ // Could be refactored as it occurs in multiple places
+ item.offers?.forEach((o) => {
+ const offer = tags.find((t) => t.id === o.tags_id)
+ offer && itemTags.push(offer)
+ })
+ item.needs?.forEach((n) => {
+ const need = tags.find((t) => t.id === n.tags_id)
+ need && itemTags.push(need)
+ })
return itemTags
},
diff --git a/src/Components/Profile/ProfileForm.tsx b/src/Components/Profile/ProfileForm.tsx
index c5339657..8b25baad 100644
--- a/src/Components/Profile/ProfileForm.tsx
+++ b/src/Components/Profile/ProfileForm.tsx
@@ -1,8 +1,5 @@
-/* eslint-disable @typescript-eslint/no-unsafe-member-access */
-/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/restrict-template-expressions */
/* eslint-disable @typescript-eslint/no-unnecessary-condition */
-/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/no-unsafe-argument */
import { useEffect, useState } from 'react'
import { useLocation, useNavigate } from 'react-router-dom'
@@ -14,7 +11,6 @@ import { useLayers } from '#components/Map/hooks/useLayers'
import { useHasUserPermission } from '#components/Map/hooks/usePermissions'
import { useAddTag, useGetItemTags, useTags } from '#components/Map/hooks/useTags'
import { MapOverlayPage } from '#components/Templates'
-import { getValue } from '#utils/GetValue'
import { linkItem, onUpdateItem, unlinkItem } from './itemFunctions'
import { FormHeader } from './Subcomponents/FormHeader'
@@ -23,11 +19,12 @@ import { OnepagerForm } from './Templates/OnepagerForm'
import { SimpleForm } from './Templates/SimpleForm'
import { TabsForm } from './Templates/TabsForm'
+import type { FormState } from '#types/FormState'
import type { Item } from '#types/Item'
import type { Tag } from '#types/Tag'
export function ProfileForm() {
- const [state, setState] = useState({
+ const [state, setState] = useState({
color: '',
id: '',
group_type: 'wuerdekompass',
@@ -91,11 +88,10 @@ export function ProfileForm() {
useEffect(() => {
const newColor =
- item.layer?.itemColorField && getValue(item, item.layer.itemColorField)
- ? getValue(item, item.layer.itemColorField)
- : getItemTags(item) && getItemTags(item)[0]?.color
- ? getItemTags(item)[0].color
- : item.layer?.markerDefaultColor
+ item.color ??
+ (getItemTags(item) && getItemTags(item)[0]?.color
+ ? getItemTags(item)[0].color
+ : item.layer?.markerDefaultColor)
const offers = (item.offers ?? []).reduce((acc: Tag[], o) => {
const offer = tags.find((t) => t.id === o.tags_id)
@@ -116,7 +112,7 @@ export function ProfileForm() {
}, [])
setState({
- color: newColor,
+ color: newColor ?? '',
id: item?.id ?? '',
group_type: item?.group_type ?? '',
status: item?.status ?? '',
@@ -127,7 +123,8 @@ export function ProfileForm() {
telephone: item?.telephone ?? '',
next_appointment: item?.next_appointment ?? '',
image: item?.image ?? '',
- marker_icon: item?.marker_icon ?? '',
+ // Do we actually mean marker_icon here?
+ marker_icon: item?.markerIcon ?? '',
offers,
needs,
relations,
@@ -140,7 +137,7 @@ export function ProfileForm() {
const [template, setTemplate] = useState('')
useEffect(() => {
- setTemplate(item.layer?.itemType.template || appState.userType)
+ setTemplate(item.layer?.itemType.template ?? appState.userType)
}, [appState.userType, item])
return (
@@ -198,7 +195,8 @@ export function ProfileForm() {
className={loading ? ' tw-loading tw-btn tw-float-right' : 'tw-btn tw-float-right'}
type='submit'
style={{
- backgroundColor: `${item.layer?.itemColorField && getValue(item, item.layer?.itemColorField) ? getValue(item, item.layer?.itemColorField) : getItemTags(item) && getItemTags(item)[0] && getItemTags(item)[0].color ? getItemTags(item)[0].color : item?.layer?.markerDefaultColor}`,
+ // We could refactor this, it is used several times at different locations
+ backgroundColor: `${item.color ?? (getItemTags(item) && getItemTags(item)[0] && getItemTags(item)[0].color ? getItemTags(item)[0].color : item?.layer?.markerDefaultColor)}`,
color: '#fff',
}}
>
diff --git a/src/Components/Profile/ProfileView.tsx b/src/Components/Profile/ProfileView.tsx
index 76c42aec..b4b05b5e 100644
--- a/src/Components/Profile/ProfileView.tsx
+++ b/src/Components/Profile/ProfileView.tsx
@@ -1,10 +1,10 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
-/* eslint-disable @typescript-eslint/await-thenable */
+
/* eslint-disable @typescript-eslint/no-non-null-assertion */
/* eslint-disable @typescript-eslint/no-non-null-asserted-optional-chain */
/* eslint-disable @typescript-eslint/no-unsafe-argument */
-/* eslint-disable @typescript-eslint/no-floating-promises */
+
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-call */
import { LatLng } from 'leaflet'
@@ -21,7 +21,6 @@ import { useSelectPosition, useSetSelectPosition } from '#components/Map/hooks/u
import { useTags } from '#components/Map/hooks/useTags'
import { HeaderView } from '#components/Map/Subcomponents/ItemPopupComponents/HeaderView'
import { MapOverlayPage } from '#components/Templates'
-import { getValue } from '#utils/GetValue'
import { handleDelete, linkItem, unlinkItem } from './itemFunctions'
import { FlexView } from './Templates/FlexView'
@@ -32,6 +31,7 @@ import { TabsView } from './Templates/TabsView'
import type { Item } from '#types/Item'
import type { ItemsApi } from '#types/ItemsApi'
import type { Tag } from '#types/Tag'
+import type { Marker } from 'leaflet'
export function ProfileView({ attestationApi }: { attestationApi?: ItemsApi }) {
const [item, setItem] = useState- ()
@@ -88,30 +88,25 @@ export function ProfileView({ attestationApi }: { attestationApi?: ItemsApi
setNeeds([])
setRelations([])
- item?.layer?.itemOffersField &&
- getValue(item, item.layer.itemOffersField)?.map((o) => {
- const tag = tags.find((t) => t.id === o.tags_id)
- tag && setOffers((current) => [...current, tag])
- return null
- })
- item?.layer?.itemNeedsField &&
- getValue(item, item.layer.itemNeedsField)?.map((n) => {
- const tag = tags.find((t) => t.id === n.tags_id)
- tag && setNeeds((current) => [...current, tag])
- return null
- })
- item?.relations?.map((r) => {
+ item?.offers?.forEach((o) => {
+ const tag = tags.find((t) => t.id === o.tags_id)
+ tag && setOffers((current) => [...current, tag])
+ })
+ item?.needs?.forEach((n) => {
+ const tag = tags.find((t) => t.id === n.tags_id)
+ tag && setNeeds((current) => [...current, tag])
+ })
+ item?.relations?.forEach((r) => {
const item = items.find((i) => i.id === r.related_items_id)
item && setRelations((current) => [...current, item])
- return null
})
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [item, items])
useEffect(() => {
- const setMap = async (marker, x) => {
- await map.setView(
+ const setMap = (marker: Marker, x: number) => {
+ map.setView(
new LatLng(item?.position?.coordinates[1]!, item?.position?.coordinates[0]! + x / 4),
undefined,
)
@@ -164,7 +159,7 @@ export function ProfileView({ attestationApi }: { attestationApi?: ItemsApi
}, [selectPosition])
useEffect(() => {
- setTemplate(item?.layer?.itemType.template || appState.userType)
+ setTemplate(item?.layer?.itemType.template ?? appState.userType)
}, [appState.userType, item])
return (
diff --git a/src/Components/Profile/Subcomponents/ActionsButton.tsx b/src/Components/Profile/Subcomponents/ActionsButton.tsx
index 7eea5e44..f261dfb7 100644
--- a/src/Components/Profile/Subcomponents/ActionsButton.tsx
+++ b/src/Components/Profile/Subcomponents/ActionsButton.tsx
@@ -10,7 +10,6 @@ import { useHasUserPermission } from '#components/Map/hooks/usePermissions'
import { useGetItemTags } from '#components/Map/hooks/useTags'
import { HeaderView } from '#components/Map/Subcomponents/ItemPopupComponents/HeaderView'
import DialogModal from '#components/Templates/DialogModal'
-import { getValue } from '#utils/GetValue'
import type { Item } from '#types/Item'
@@ -20,7 +19,6 @@ export function ActionButton({
triggerItemSelected,
existingRelations,
itemType,
- colorField,
collection = 'items',
customStyle,
}: {
@@ -28,7 +26,6 @@ export function ActionButton({
triggerItemSelected?: any
existingRelations: Item[]
itemType?: string
- colorField?: string
collection?: string
customStyle?: string
item: Item
@@ -45,6 +42,12 @@ export function ActionButton({
.filter((i) => !existingRelations.some((s) => s.id === i.id))
.filter((i) => i.id !== item.id)
+ const backgroundColor =
+ item.color ??
+ (getItemTags(item) && getItemTags(item)[0] && getItemTags(item)[0].color
+ ? getItemTags(item)[0].color
+ : item.layer?.markerDefaultColor)
+
return (
<>
{hasUserPermission(collection, 'update', item) && (
@@ -58,7 +61,7 @@ export function ActionButton({
setModalOpen(true)
}}
style={{
- backgroundColor: `${colorField && getValue(item, colorField) ? getValue(item, colorField) : getItemTags(item) && getItemTags(item)[0] && getItemTags(item)[0].color ? getItemTags(item)[0].color : item.layer?.markerDefaultColor}`,
+ backgroundColor,
color: '#fff',
}}
>
@@ -82,7 +85,7 @@ export function ActionButton({
triggerAddButton()
}}
style={{
- backgroundColor: `${colorField && getValue(item, colorField) ? getValue(item, colorField) : getItemTags(item) && getItemTags(item)[0] && getItemTags(item)[0].color ? getItemTags(item)[0].color : item.layer?.markerDefaultColor}`,
+ backgroundColor,
color: '#fff',
}}
>
diff --git a/src/Components/Profile/Subcomponents/AvatarWidget.tsx b/src/Components/Profile/Subcomponents/AvatarWidget.tsx
index ab4be26d..b67c2c52 100644
--- a/src/Components/Profile/Subcomponents/AvatarWidget.tsx
+++ b/src/Components/Profile/Subcomponents/AvatarWidget.tsx
@@ -6,7 +6,6 @@ import { useState, useCallback, useRef } from 'react'
import { ReactCrop, centerCrop, makeAspectCrop } from 'react-image-crop'
import { useAppState } from '#components/AppShell/hooks/useAppState'
-// eslint-disable-next-line import/no-unassigned-import
import 'react-image-crop/dist/ReactCrop.css'
import DialogModal from '#components/Templates/DialogModal'
diff --git a/src/Components/Profile/Subcomponents/ColorPicker.tsx b/src/Components/Profile/Subcomponents/ColorPicker.tsx
index abe199f7..84160fc0 100644
--- a/src/Components/Profile/Subcomponents/ColorPicker.tsx
+++ b/src/Components/Profile/Subcomponents/ColorPicker.tsx
@@ -5,7 +5,6 @@
import { useCallback, useEffect, useRef, useState } from 'react'
import { HexColorPicker } from 'react-colorful'
-// eslint-disable-next-line import/no-unassigned-import
import './ColorPicker.css'
import useClickOutside from '#components/Profile/hooks/useClickOutside'
diff --git a/src/Components/Profile/Subcomponents/ContactInfoView.tsx b/src/Components/Profile/Subcomponents/ContactInfoView.tsx
index a8368d24..34e6b8fa 100644
--- a/src/Components/Profile/Subcomponents/ContactInfoView.tsx
+++ b/src/Components/Profile/Subcomponents/ContactInfoView.tsx
@@ -1,5 +1,5 @@
/* eslint-disable @typescript-eslint/no-unnecessary-condition */
-/* eslint-disable @typescript-eslint/restrict-template-expressions */
+
/* eslint-disable @typescript-eslint/no-unsafe-return */
/* eslint-disable @typescript-eslint/restrict-plus-operands */
import { useEffect, useState } from 'react'
diff --git a/src/Components/Profile/Subcomponents/GalleryView.tsx b/src/Components/Profile/Subcomponents/GalleryView.tsx
new file mode 100644
index 00000000..affd8515
--- /dev/null
+++ b/src/Components/Profile/Subcomponents/GalleryView.tsx
@@ -0,0 +1,36 @@
+import { useState } from 'react'
+import { RowsPhotoAlbum } from 'react-photo-album'
+import ReactLightbox from 'yet-another-react-lightbox'
+import 'yet-another-react-lightbox/styles.css'
+import 'react-photo-album/rows.css'
+
+import { useAppState } from '#components/AppShell/hooks/useAppState'
+
+import type { Item } from '#types/Item'
+
+export const GalleryView = ({ item }: { item: Item }) => {
+ const [index, setIndex] = useState(-1)
+ const appState = useAppState()
+ const images = item.gallery?.map((i, j) => {
+ return {
+ src: appState.assetsApi.url + `${i.directus_files_id.id}.jpg`,
+ width: i.directus_files_id.width,
+ height: i.directus_files_id.height,
+ index: j,
+ }
+ })
+
+ if (!images) throw new Error('GalleryView: images is undefined')
+
+ return (
+
+ setIndex(current)}
+ />
+
+ = 0} close={() => setIndex(-1)} />
+
+ )
+}
diff --git a/src/Components/Profile/Subcomponents/LinkedItemsHeaderView.tsx b/src/Components/Profile/Subcomponents/LinkedItemsHeaderView.tsx
index 57dd0ce9..6c205aa7 100644
--- a/src/Components/Profile/Subcomponents/LinkedItemsHeaderView.tsx
+++ b/src/Components/Profile/Subcomponents/LinkedItemsHeaderView.tsx
@@ -4,46 +4,29 @@
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/restrict-plus-operands */
/* eslint-disable @typescript-eslint/no-unnecessary-condition */
-/* eslint-disable @typescript-eslint/no-unsafe-assignment */
+
import { useEffect } from 'react'
import { useAppState } from '#components/AppShell/hooks/useAppState'
-import { getValue } from '#utils/GetValue'
import type { Item } from '#types/Item'
export function LinkedItemsHeaderView({
item,
unlinkCallback,
- itemNameField,
- itemAvatarField,
loading,
unlinkPermission,
- itemSubnameField,
}: {
item: Item
unlinkCallback?: any
- itemNameField?: string
- itemAvatarField?: string
- itemSubnameField?: string
loading?: boolean
unlinkPermission: boolean
}) {
const appState = useAppState()
- const avatar =
- itemAvatarField && getValue(item, itemAvatarField)
- ? appState.assetsApi.url + getValue(item, itemAvatarField)
- : item.layer?.itemAvatarField &&
- item &&
- getValue(item, item.layer?.itemAvatarField) &&
- appState.assetsApi.url + getValue(item, item.layer?.itemAvatarField)
- 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)
+ const avatar = appState.assetsApi.url + item.image
+ const title = item.name
+ const subtitle = item.subname
useEffect(() => {}, [item])
diff --git a/src/Components/Profile/Subcomponents/ProfileTextForm.tsx b/src/Components/Profile/Subcomponents/ProfileTextForm.tsx
index 1d72a3b3..2620aecd 100644
--- a/src/Components/Profile/Subcomponents/ProfileTextForm.tsx
+++ b/src/Components/Profile/Subcomponents/ProfileTextForm.tsx
@@ -5,7 +5,6 @@
import { useEffect, useState } from 'react'
import { TextAreaInput } from '#components/Input'
-import { getValue } from '#utils/GetValue'
import { MarkdownHint } from './MarkdownHint'
@@ -14,6 +13,7 @@ import type { FormState } from '#types/FormState'
export const ProfileTextForm = ({
state,
setState,
+ // Is this really used?
dataField,
heading,
size,
@@ -49,7 +49,8 @@ export const ProfileTextForm = ({
setState((prevState) => ({
...prevState,
diff --git a/src/Components/Profile/Subcomponents/ProfileTextView.tsx b/src/Components/Profile/Subcomponents/ProfileTextView.tsx
index 8a2725ce..9fc35bbb 100644
--- a/src/Components/Profile/Subcomponents/ProfileTextView.tsx
+++ b/src/Components/Profile/Subcomponents/ProfileTextView.tsx
@@ -1,12 +1,12 @@
-/* eslint-disable @typescript-eslint/no-unsafe-assignment */
+import { get } from 'radash'
+
import { TextView } from '#components/Map'
-import { getValue } from '#utils/GetValue'
import type { Item } from '#types/Item'
export const ProfileTextView = ({
item,
- dataField,
+ dataField = 'text',
heading,
hideWhenEmpty,
}: {
@@ -15,13 +15,19 @@ export const ProfileTextView = ({
heading: string
hideWhenEmpty: boolean
}) => {
+ const text = get(item, dataField)
+
+ if (typeof text !== 'string') {
+ throw new Error('ProfileTextView: text is not a string')
+ }
+
return (
- {!(getValue(item, dataField) === '' && hideWhenEmpty) && (
+ {!(text === '' && hideWhenEmpty) && (
{heading}
)}
-
+
)
diff --git a/src/Components/Profile/Templates/FlexForm.tsx b/src/Components/Profile/Templates/FlexForm.tsx
index 56f14eac..5e8d4408 100644
--- a/src/Components/Profile/Templates/FlexForm.tsx
+++ b/src/Components/Profile/Templates/FlexForm.tsx
@@ -1,7 +1,5 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
-/* eslint-disable @typescript-eslint/no-unsafe-member-access */
-/* eslint-disable @typescript-eslint/no-unsafe-call */
import { ContactInfoForm } from '#components/Profile/Subcomponents/ContactInfoForm'
import { GroupSubheaderForm } from '#components/Profile/Subcomponents/GroupSubheaderForm'
diff --git a/src/Components/Profile/Templates/FlexView.tsx b/src/Components/Profile/Templates/FlexView.tsx
index 1dea72d6..2d98ec74 100644
--- a/src/Components/Profile/Templates/FlexView.tsx
+++ b/src/Components/Profile/Templates/FlexView.tsx
@@ -1,19 +1,20 @@
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
-/* eslint-disable @typescript-eslint/no-unsafe-member-access */
-/* eslint-disable @typescript-eslint/no-unsafe-call */
import { ContactInfoView } from '#components/Profile/Subcomponents/ContactInfoView'
+import { GalleryView } from '#components/Profile/Subcomponents/GalleryView'
import { GroupSubHeaderView } from '#components/Profile/Subcomponents/GroupSubHeaderView'
import { ProfileStartEndView } from '#components/Profile/Subcomponents/ProfileStartEndView'
import { ProfileTextView } from '#components/Profile/Subcomponents/ProfileTextView'
import type { Item } from '#types/Item'
+import type { Key } from 'react'
const componentMap = {
groupSubheaders: GroupSubHeaderView,
texts: ProfileTextView,
contactInfos: ContactInfoView,
startEnd: ProfileStartEndView,
+ gallery: GalleryView,
// weitere Komponenten hier
}
@@ -22,14 +23,17 @@ export const FlexView = ({ item }: { item: Item }) => {
console.log(item)
return (
- {item.layer?.itemType.profileTemplate.map((templateItem) => {
- const TemplateComponent = componentMap[templateItem.collection]
- return TemplateComponent ? (
-
- ) : (
-
Component not found
- )
- })}
+ {item.layer?.itemType.profileTemplate.map(
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ (templateItem: { collection: string | number; id: Key | null | undefined; item: any }) => {
+ const TemplateComponent = componentMap[templateItem.collection]
+ return TemplateComponent ? (
+
+ ) : (
+
Component not found
+ )
+ },
+ )}
)
}
diff --git a/src/Components/Profile/Templates/OnepagerView.tsx b/src/Components/Profile/Templates/OnepagerView.tsx
index 32a786ee..1993fef5 100644
--- a/src/Components/Profile/Templates/OnepagerView.tsx
+++ b/src/Components/Profile/Templates/OnepagerView.tsx
@@ -1,4 +1,3 @@
-/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/restrict-template-expressions */
import { TextView } from '#components/Map'
import { ContactInfoView } from '#components/Profile/Subcomponents/ContactInfoView'
@@ -16,14 +15,14 @@ export const OnepagerView = ({ item }: { item: Item }) => {
{item.user_created?.first_name && }
{/* Description Section */}
-
+
{/* Next Appointment Section */}
{item.next_appointment && (
)}
diff --git a/src/Components/Profile/Templates/SimpleView.tsx b/src/Components/Profile/Templates/SimpleView.tsx
index dca6d079..b7d7776a 100644
--- a/src/Components/Profile/Templates/SimpleView.tsx
+++ b/src/Components/Profile/Templates/SimpleView.tsx
@@ -5,7 +5,7 @@ import type { Item } from '#types/Item'
export const SimpleView = ({ item }: { item: Item }) => {
return (
-
+
)
}
diff --git a/src/Components/Profile/Templates/TabsForm.tsx b/src/Components/Profile/Templates/TabsForm.tsx
index add01201..a2686366 100644
--- a/src/Components/Profile/Templates/TabsForm.tsx
+++ b/src/Components/Profile/Templates/TabsForm.tsx
@@ -113,6 +113,7 @@ export const TabsForm = ({
}
inputStyle='tw-h-24'
containerStyle='tw-pt-4'
+ required={false}
/>