/* eslint-disable camelcase */ // Directus database fields use snake_case /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-misused-promises */ /* eslint-disable @typescript-eslint/no-non-null-assertion */ /* eslint-disable @typescript-eslint/no-unsafe-call */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-argument */ import { useEffect, useRef, useState } from 'react' import { toast } from 'react-toastify' import { useAuth } from '#components/Auth/useAuth' import { TextInput } from '#components/Input' import { useFilterTags } from '#components/Map/hooks/useFilter' import { useAddItem, useItems, useRemoveItem } from '#components/Map/hooks/useItems' import { useLayers } from '#components/Map/hooks/useLayers' import { useAddTag, useGetItemTags, useTags } from '#components/Map/hooks/useTags' import { Control } from '#components/Map/Subcomponents/Controls/Control' import { SearchControl } from '#components/Map/Subcomponents/Controls/SearchControl' import { TagsControl } from '#components/Map/Subcomponents/Controls/TagsControl' import { PopupStartEndInput } from '#components/Map/Subcomponents/ItemPopupComponents' import { PlusButton } from '#components/Profile/Subcomponents/PlusButton' import { hashTagRegex } from '#utils/HashTagRegex' import { randomColor } from '#utils/RandomColor' import { filterSortAndPaginate } from './filterSortAndPaginate' import { ItemCard } from './ItemCard' import { MapOverlayPage } from './MapOverlayPage' import type { Item } from '#types/Item' /** * @category Templates */ export const OverlayItemsIndexPage = ({ url, layerName, }: { layerName: string url: string parameterField?: string }) => { const [loading, setLoading] = useState(false) const [addItemPopupOpen, setAddItemPopupOpen] = useState(false) const [itemsToShow, setItemsToShow] = useState(30) const tabRef = useRef(null) const sentinelRef = useRef(null) const scrollContainerRef = useRef(null) const isLoadingMoreRef = useRef(false) function scroll() { tabRef.current?.scrollIntoView() } useEffect(() => { if (addItemPopupOpen) { scroll() } }, [addItemPopupOpen]) const tags = useTags() const addTag = useAddTag() const { user } = useAuth() const items = useItems() const addItem = useAddItem() const removeItem = useRemoveItem() const layers = useLayers() const filterTags = useFilterTags() const getItemTags = useGetItemTags() const layer = layers.find((l) => l.name === layerName) const { visibleItems, hasMore } = filterSortAndPaginate( items, layerName, filterTags, getItemTags, itemsToShow, ) useEffect(() => { const sentinel = sentinelRef.current const scrollContainer = scrollContainerRef.current if (!sentinel || !scrollContainer) return const observer = new IntersectionObserver( (entries) => { const entry = entries[0] if (entry.isIntersecting && !isLoadingMoreRef.current && hasMore) { isLoadingMoreRef.current = true setItemsToShow((prev) => prev + 24) } }, { root: scrollContainer, rootMargin: '400px', threshold: 0.1, }, ) observer.observe(sentinel) return () => { observer.disconnect() } }, [hasMore, visibleItems.length]) useEffect(() => { isLoadingMoreRef.current = false }, [visibleItems.length]) const submitNewItem = async (evt: React.FormEvent) => { evt.preventDefault() const formItem: Item = {} as Item Array.from(evt.target as any).forEach((input: HTMLInputElement) => { if (input.name) { formItem[input.name] = input.value } }) setLoading(true) if (formItem.text) { formItem.text .toLocaleLowerCase() .match(hashTagRegex) ?.map((tag) => { if (!tags.find((t) => t.name.toLocaleLowerCase() === tag.slice(1).toLocaleLowerCase())) { addTag({ id: crypto.randomUUID(), name: tag.slice(1), color: randomColor() }) } return null }) } const uuid = crypto.randomUUID() let success = false try { await layer?.api?.createItem!({ ...formItem, id: uuid }) success = true // eslint-disable-next-line no-catch-all/no-catch-all } catch (error) { toast.error(error.toString()) } if (success) { toast.success('New item created') } addItem({ ...formItem, user_created: user ?? undefined, id: uuid, layer, public_edit: !user }) setLoading(false) setAddItemPopupOpen(false) } const deleteItem = async (item: Item) => { setLoading(true) let success = false try { await layer?.api?.deleteItem!(item.id) success = true // eslint-disable-next-line no-catch-all/no-catch-all } catch (error) { toast.error(error.toString()) } if (success) { toast.success('Item deleted') } removeItem(item) setLoading(false) } return ( <>
{visibleItems.map((i) => (
deleteItem(i)} />
))} {addItemPopupOpen && (
submitNewItem(e)}>
{layer?.menuText}
{layer?.itemType.show_start_end_input && ( )}
)}
{hasMore && (
)}
{!layer?.userProfileLayer && ( { setAddItemPopupOpen(true) scroll() }} color={'#777'} collection='items' /> )} ) }