mirror of
https://github.com/utopia-os/utopia-ui.git
synced 2025-12-13 07:46:10 +00:00
181 lines
4.7 KiB
TypeScript
181 lines
4.7 KiB
TypeScript
import { useCallback, useReducer, createContext, useContext, useState } from 'react'
|
|
import * as React from 'react'
|
|
import { Item, LayerProps } from '../../../types'
|
|
import { toast } from 'react-toastify'
|
|
import { useAddLayer } from './useLayers'
|
|
|
|
type ActionType =
|
|
| { type: 'ADD'; item: Item }
|
|
| { type: 'UPDATE'; item: Item }
|
|
| { type: 'REMOVE'; item: Item }
|
|
| { type: 'RESET'; layer: LayerProps }
|
|
|
|
type UseItemManagerResult = ReturnType<typeof useItemsManager>
|
|
|
|
const ItemContext = createContext<UseItemManagerResult>({
|
|
items: [],
|
|
addItem: () => {},
|
|
updateItem: () => {},
|
|
removeItem: () => {},
|
|
resetItems: () => {},
|
|
setItemsApi: () => {},
|
|
setItemsData: () => {},
|
|
allItemsLoaded: false,
|
|
})
|
|
|
|
function useItemsManager(initialItems: Item[]): {
|
|
items: Item[]
|
|
addItem: (item: Item) => void
|
|
updateItem: (item: Item) => void
|
|
removeItem: (item: Item) => void
|
|
resetItems: (layer: LayerProps) => void
|
|
setItemsApi: (layer: LayerProps) => void
|
|
setItemsData: (layer: LayerProps) => void
|
|
allItemsLoaded: boolean
|
|
} {
|
|
const addLayer = useAddLayer()
|
|
|
|
const [allItemsLoaded, setallItemsLoaded] = useState<boolean>(false)
|
|
|
|
const [items, dispatch] = useReducer((state: Item[], action: ActionType) => {
|
|
switch (action.type) {
|
|
case 'ADD':
|
|
// eslint-disable-next-line no-case-declarations
|
|
const exist = state.find((item) => item.id === action.item.id)
|
|
if (!exist) {
|
|
return [...state, action.item]
|
|
} else return state
|
|
case 'UPDATE':
|
|
return state.map((item) => {
|
|
if (item.id === action.item.id) {
|
|
return action.item
|
|
}
|
|
return item
|
|
})
|
|
case 'REMOVE':
|
|
return state.filter((item) => item !== action.item)
|
|
case 'RESET':
|
|
return state.filter((item) => item.layer?.name !== action.layer.name)
|
|
default:
|
|
throw new Error()
|
|
}
|
|
}, initialItems)
|
|
|
|
const setItemsApi = useCallback(async (layer: LayerProps) => {
|
|
addLayer(layer)
|
|
const result = await toast.promise(layer.api!.getItems(), {
|
|
pending: `loading ${layer.name} ...`,
|
|
success: `${layer.name} loaded`,
|
|
error: {
|
|
render({ data }) {
|
|
return `${data}`
|
|
},
|
|
},
|
|
})
|
|
if (result) {
|
|
result.map((item) => {
|
|
dispatch({ type: 'ADD', item: { ...item, layer } })
|
|
return null
|
|
})
|
|
setallItemsLoaded(true)
|
|
}
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [])
|
|
|
|
const setItemsData = useCallback((layer: LayerProps) => {
|
|
addLayer(layer)
|
|
layer.data?.map((item) => {
|
|
dispatch({ type: 'ADD', item: { ...item, layer } })
|
|
return null
|
|
})
|
|
setallItemsLoaded(true)
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [])
|
|
|
|
const addItem = useCallback(async (item: Item) => {
|
|
dispatch({
|
|
type: 'ADD',
|
|
item,
|
|
})
|
|
}, [])
|
|
|
|
const updateItem = useCallback(async (item: Item) => {
|
|
dispatch({
|
|
type: 'UPDATE',
|
|
item,
|
|
})
|
|
}, [])
|
|
|
|
const removeItem = useCallback((item: Item) => {
|
|
dispatch({
|
|
type: 'REMOVE',
|
|
item,
|
|
})
|
|
}, [])
|
|
|
|
const resetItems = useCallback((layer: LayerProps) => {
|
|
dispatch({
|
|
type: 'RESET',
|
|
layer,
|
|
})
|
|
}, [])
|
|
|
|
return {
|
|
items,
|
|
updateItem,
|
|
addItem,
|
|
removeItem,
|
|
resetItems,
|
|
setItemsApi,
|
|
setItemsData,
|
|
allItemsLoaded,
|
|
}
|
|
}
|
|
|
|
export const ItemsProvider: React.FunctionComponent<{
|
|
initialItems: Item[]
|
|
children?: React.ReactNode
|
|
}> = ({ initialItems, children }) => (
|
|
<ItemContext.Provider value={useItemsManager(initialItems)}>{children}</ItemContext.Provider>
|
|
)
|
|
|
|
export const useItems = (): Item[] => {
|
|
const { items } = useContext(ItemContext)
|
|
return items
|
|
}
|
|
|
|
export const useAddItem = (): UseItemManagerResult['addItem'] => {
|
|
const { addItem } = useContext(ItemContext)
|
|
return addItem
|
|
}
|
|
|
|
export const useUpdateItem = (): UseItemManagerResult['updateItem'] => {
|
|
const { updateItem } = useContext(ItemContext)
|
|
return updateItem
|
|
}
|
|
|
|
export const useRemoveItem = (): UseItemManagerResult['removeItem'] => {
|
|
const { removeItem } = useContext(ItemContext)
|
|
return removeItem
|
|
}
|
|
|
|
export const useResetItems = (): UseItemManagerResult['resetItems'] => {
|
|
const { resetItems } = useContext(ItemContext)
|
|
return resetItems
|
|
}
|
|
|
|
export const useSetItemsApi = (): UseItemManagerResult['setItemsApi'] => {
|
|
const { setItemsApi } = useContext(ItemContext)
|
|
return setItemsApi
|
|
}
|
|
|
|
export const useSetItemsData = (): UseItemManagerResult['setItemsData'] => {
|
|
const { setItemsData } = useContext(ItemContext)
|
|
return setItemsData
|
|
}
|
|
|
|
export const useAllItemsLoaded = (): UseItemManagerResult['allItemsLoaded'] => {
|
|
const { allItemsLoaded } = useContext(ItemContext)
|
|
return allItemsLoaded
|
|
}
|