fix(source): select position on index page (#240)

* 3.0.97

* 3.0.98

* 3.0.99

* add select position to item menu on index page

* added tooltips to headermenu

* optimized toasts while updating item position
This commit is contained in:
Anton Tranelis 2025-06-11 13:04:04 +02:00 committed by GitHub
parent a7a50af896
commit 55c39bef88
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 80 additions and 25 deletions

View File

@ -137,7 +137,8 @@ export function HeaderView({
editCallback && (
<li>
<a
className='tw:text-base-content! tw:cursor-pointer'
className='tw:text-base-content! tw:tooltip tw:tooltip-right tw:cursor-pointer'
data-tip='Edit'
onClick={(e) =>
item.layer?.customEditLink
? navigate(
@ -155,7 +156,8 @@ export function HeaderView({
setPositionCallback && (
<li>
<a
className='tw:text-base-content! tw:cursor-pointer'
className='tw:text-base-content! tw:tooltip tw:tooltip-right tw:cursor-pointer'
data-tip='Set position'
onClick={setPositionCallback}
>
<SVG src={TargetDotSVG} className='tw:w-5 tw:h-5' />
@ -166,7 +168,11 @@ export function HeaderView({
hasUserPermission(api.collectionName!, 'delete', item) &&
deleteCallback && (
<li>
<a className='tw:cursor-pointer tw:text-error!' onClick={openDeleteModal}>
<a
className='tw:text-error! tw:tooltip tw:tooltip-right tw:cursor-pointer'
data-tip='Delete'
onClick={openDeleteModal}
>
{loading ? (
<span className='tw:loading tw:loading-spinner tw:loading-sm'></span>
) : (

View File

@ -1,5 +1,13 @@
/* eslint-disable @typescript-eslint/no-unsafe-call */
export const SelectPosition = ({ setSelectNewItemPosition }: { setSelectNewItemPosition }) => {
import type { Item } from '#types/Item'
import type { LayerProps } from '#types/LayerProps'
export const SelectPosition = ({
setSelectNewItemPosition,
selectNewItemPosition,
}: {
setSelectNewItemPosition: React.Dispatch<React.SetStateAction<Item | LayerProps | null>>
selectNewItemPosition?: Item | LayerProps | null
}) => {
return (
<div className='tw:animate-pulseGrow tw:button tw:z-1000 tw:absolute tw:right-5 tw:top-4 tw:drop-shadow-md'>
<label
@ -12,7 +20,14 @@ export const SelectPosition = ({ setSelectNewItemPosition }: { setSelectNewItemP
</label>
<div className='tw:alert tw:bg-base-100 tw:text-base-content'>
<div>
<span className='tw:text-lg'>Select position on the map!</span>
{selectNewItemPosition && 'text' in selectNewItemPosition && (
<span className='tw:text-lg'>
Select new position of <b>{selectNewItemPosition.name}</b> on the map!
</span>
)}
{selectNewItemPosition && 'menuIcon' in selectNewItemPosition && (
<span className='tw:text-lg'>Select position on the map!</span>
)}
</div>
</div>
</div>

View File

@ -307,7 +307,10 @@ export function UtopiaMapInner({
<MapEventListener />
<AddButton triggerAction={setSelectNewItemPosition} />
{selectNewItemPosition != null && (
<SelectPosition setSelectNewItemPosition={setSelectNewItemPosition} />
<SelectPosition
selectNewItemPosition={selectNewItemPosition}
setSelectNewItemPosition={setSelectNewItemPosition}
/>
)}
</div>
)

View File

@ -5,8 +5,7 @@
/* eslint-disable @typescript-eslint/prefer-nullish-coalescing */
/* eslint-disable @typescript-eslint/await-thenable */
/* eslint-disable @typescript-eslint/restrict-plus-operands */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-non-null-assertion */
import { createContext, useContext, useEffect, useState } from 'react'
import { toast } from 'react-toastify'
@ -87,6 +86,7 @@ function useSelectPositionManager(): {
}, [mapClicked])
const itemUpdateParent = async (updatedItem: Item) => {
const toastId = toast.loading('Adding item to ' + markerClicked?.name)
if (
markerClicked?.layer?.api?.collectionName &&
hasUserPermission(markerClicked.layer.api.collectionName, 'update', markerClicked)
@ -99,40 +99,57 @@ function useSelectPositionManager(): {
position: null,
})
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())
} catch (error: unknown) {
if (error instanceof Error) {
toast.update(toastId, { render: error.message, type: 'error' })
} else if (typeof error === 'string') {
toast.update(toastId, { render: error, type: 'error' })
} else {
throw error
}
}
if (success) {
await updateItem({ ...updatedItem, parent: updatedItem.parent, position: undefined })
await linkItem(updatedItem.id)
toast.success('Item position updated')
toast.update(toastId, {
render: 'Item position updated',
type: 'success',
isLoading: false,
})
setSelectPosition(null)
setMarkerClicked(null)
}
} else {
setSelectPosition(null)
toast.error("you don't have permission to add items to " + markerClicked?.name)
toast.update(toastId, {
render: "you don't have permission to add items to " + markerClicked?.name,
type: 'error',
isLoading: false,
})
}
}
const itemUpdatePosition = async (updatedItem: Item) => {
let success = false
const toastId = toast.loading('Updating item position')
try {
await updatedItem.layer?.api?.updateItem!({
id: updatedItem.id,
position: updatedItem.position,
})
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())
} catch (error: unknown) {
if (error instanceof Error) {
toast.update(toastId, { render: error.message, type: 'error', isLoading: false })
} else if (typeof error === 'string') {
toast.update(toastId, { render: error, type: 'error', isLoading: false })
} else {
throw error
}
}
if (success) {
updateItem(updatedItem)
toast.success('Item position updated')
toast.update(toastId, { render: 'Item position updated', type: 'success', isLoading: false })
}
}
@ -145,17 +162,22 @@ function useSelectPositionManager(): {
const updatedItem = { id: markerClicked.id, relations: newRelations }
let success = false
const toastId = toast.loading('Linking item')
try {
await markerClicked.layer?.api?.updateItem!(updatedItem)
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())
} catch (error: unknown) {
if (error instanceof Error) {
toast.update(toastId, { render: error.message, type: 'error', isLoading: false })
} else if (typeof error === 'string') {
toast.update(toastId, { render: error, type: 'error', isLoading: false })
} else {
throw error
}
}
if (success) {
updateItem({ ...markerClicked, relations: newRelations })
toast.success('Item linked')
toast.update(toastId, { render: 'Item linked', type: 'success', isLoading: false })
}
}
}

View File

@ -1,5 +1,7 @@
import { useMap } from 'react-leaflet'
import { useNavigate } from 'react-router-dom'
import { useSetSelectPosition } from '#components/Map/hooks/useSelectPosition'
import useWindowDimensions from '#components/Map/hooks/useWindowDimension'
import { StartEndView, TextView } from '#components/Map/Subcomponents/ItemPopupComponents'
import { HeaderView } from '#components/Map/Subcomponents/ItemPopupComponents/HeaderView'
@ -21,6 +23,8 @@ export const ItemCard = ({
}) => {
const navigate = useNavigate()
const windowDimensions = useWindowDimensions()
const map = useMap()
const setSelectPosition = useSetSelectPosition()
return (
<div
@ -38,6 +42,11 @@ export const ItemCard = ({
item={i}
api={i.layer?.api}
editCallback={() => navigate('/edit-item/' + i.id)}
setPositionCallback={() => {
map.closePopup()
setSelectPosition(i)
navigate('/')
}}
deleteCallback={() => deleteCallback(i)}
></HeaderView>
<div className='tw:overflow-y-auto tw:overflow-x-hidden tw:max-h-64 fade'>