webapp/src/components/_shared/LoadMoreWrapper.tsx

73 lines
2.1 KiB
TypeScript
Raw Normal View History

2024-07-18 10:22:58 +00:00
import { JSX, Show, createEffect, createSignal, on, onMount } from 'solid-js'
2024-07-15 14:28:08 +00:00
import { Button } from '~/components/_shared/Button'
import { useLocalize } from '~/context/localize'
import { Author, Reaction, Shout } from '~/graphql/schema/core.gen'
2024-07-18 10:22:58 +00:00
import { SortFunction } from '~/types/common'
2024-07-15 14:28:08 +00:00
import { restoreScrollPosition, saveScrollPosition } from '~/utils/scroll'
2024-08-30 13:45:17 +00:00
import { byCreated } from '~/utils/sort'
2024-07-15 14:28:08 +00:00
2024-07-15 20:35:33 +00:00
export type LoadMoreItems = Shout[] | Author[] | Reaction[]
2024-07-15 14:28:08 +00:00
type LoadMoreProps = {
2024-07-18 10:22:58 +00:00
loadFunction: (offset: number) => Promise<LoadMoreItems>
2024-07-15 14:28:08 +00:00
pageSize: number
2024-07-16 00:14:08 +00:00
hidden?: boolean
2024-07-15 14:28:08 +00:00
children: JSX.Element
}
export const LoadMoreWrapper = (props: LoadMoreProps) => {
const { t } = useLocalize()
2024-07-15 20:35:33 +00:00
const [items, setItems] = createSignal<LoadMoreItems>([])
2024-07-15 14:28:08 +00:00
const [offset, setOffset] = createSignal(0)
2024-08-28 08:53:40 +00:00
const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(props.hidden)
2024-07-15 14:28:08 +00:00
const [isLoading, setIsLoading] = createSignal(false)
2024-07-18 10:22:58 +00:00
createEffect(
on(items, (iii) => {
2024-08-28 08:53:40 +00:00
// console.debug('LoadMoreWrapper.fx:', iii)
2024-07-18 10:22:58 +00:00
if (Array.isArray(iii)) {
setIsLoadMoreButtonVisible(iii.length - offset() >= 0)
setOffset(iii.length)
}
})
)
2024-07-15 14:28:08 +00:00
const loadItems = async () => {
setIsLoading(true)
saveScrollPosition()
const newItems = await props.loadFunction(offset())
if (!Array.isArray(newItems)) return
2024-08-28 08:53:40 +00:00
if (newItems.length === 0) setIsLoadMoreButtonVisible(false)
2024-08-29 14:40:31 +00:00
else
setItems(
(prev) =>
Array.from(new Set([...prev, ...newItems])).sort(
byCreated as SortFunction<unknown>
) as LoadMoreItems
)
2024-07-15 14:28:08 +00:00
setIsLoading(false)
restoreScrollPosition()
}
2024-09-03 10:21:59 +00:00
onMount(() => {
loadItems()
console.debug(`load on mount ${items()}`)
})
2024-07-15 14:28:08 +00:00
return (
<>
{props.children}
2024-07-26 15:49:15 +00:00
<Show when={isLoadMoreButtonVisible() && !props.hidden}>
2024-07-15 14:28:08 +00:00
<div class="load-more-container">
2024-07-26 15:49:15 +00:00
<Button
onClick={loadItems}
disabled={isLoading()}
value={t('Load more')}
title={`${items().length} ${t('loaded')}`}
/>
2024-07-15 14:28:08 +00:00
</div>
</Show>
</>
)
}