112 lines
3.4 KiB
TypeScript
112 lines
3.4 KiB
TypeScript
import { clsx } from 'clsx'
|
|
import { For, Show, createEffect, createSignal, on, onMount } from 'solid-js'
|
|
import { useFollowing } from '../../context/following'
|
|
import { useLocalize } from '../../context/localize'
|
|
import { apiClient } from '../../graphql/client/core'
|
|
import { Author } from '../../graphql/schema/core.gen'
|
|
import { setAuthorsByFollowers, setAuthorsByShouts, useAuthorsStore } from '../../stores/zine/authors'
|
|
import { AuthorBadge } from '../Author/AuthorBadge'
|
|
import { InlineLoader } from '../InlineLoader'
|
|
import { Button } from '../_shared/Button'
|
|
import styles from './AuthorsList.module.scss'
|
|
|
|
type Props = {
|
|
class?: string
|
|
query: 'followers' | 'shouts'
|
|
searchQuery?: string
|
|
allAuthorsLength?: number
|
|
}
|
|
|
|
const PAGE_SIZE = 20
|
|
|
|
export const AuthorsList = (props: Props) => {
|
|
const { t } = useLocalize()
|
|
const { isOwnerSubscribed } = useFollowing()
|
|
const { authorsByShouts, authorsByFollowers } = useAuthorsStore()
|
|
const [loading, setLoading] = createSignal(false)
|
|
const [currentPage, setCurrentPage] = createSignal({ shouts: 0, followers: 0 })
|
|
const [allLoaded, setAllLoaded] = createSignal(false)
|
|
|
|
const fetchAuthors = async (queryType: Props['query'], page: number) => {
|
|
setLoading(true)
|
|
const offset = PAGE_SIZE * page
|
|
const result = await apiClient.loadAuthorsBy({
|
|
by: { order: queryType },
|
|
limit: PAGE_SIZE,
|
|
offset,
|
|
})
|
|
|
|
if (queryType === 'shouts') {
|
|
setAuthorsByShouts((prev) => [...prev, ...result])
|
|
} else {
|
|
setAuthorsByFollowers((prev) => [...prev, ...result])
|
|
}
|
|
setLoading(false)
|
|
}
|
|
|
|
const loadMoreAuthors = () => {
|
|
const nextPage = currentPage()[props.query] + 1
|
|
fetchAuthors(props.query, nextPage).then(() =>
|
|
setCurrentPage({ ...currentPage(), [props.query]: nextPage }),
|
|
)
|
|
}
|
|
|
|
createEffect(
|
|
on(
|
|
() => props.query,
|
|
(query) => {
|
|
const authorsList = query === 'shouts' ? authorsByShouts() : authorsByFollowers()
|
|
if (authorsList.length === 0 && currentPage()[query] === 0) {
|
|
setCurrentPage((prev) => ({ ...prev, [query]: 0 }))
|
|
fetchAuthors(query, 0).then(() => setCurrentPage((prev) => ({ ...prev, [query]: 1 })))
|
|
}
|
|
},
|
|
),
|
|
)
|
|
|
|
const authorsList = () => (props.query === 'shouts' ? authorsByShouts() : authorsByFollowers())
|
|
|
|
// TODO: do it with backend
|
|
// createEffect(() => {
|
|
// if (props.searchQuery) {
|
|
// // search logic
|
|
// }
|
|
// })
|
|
|
|
createEffect(() => {
|
|
setAllLoaded(props.allAuthorsLength === authorsList.length)
|
|
})
|
|
|
|
return (
|
|
<div class={clsx(styles.AuthorsList, props.class)}>
|
|
<For each={authorsList()}>
|
|
{(author) => (
|
|
<div class="row">
|
|
<div class="col-lg-20 col-xl-18">
|
|
<AuthorBadge
|
|
author={author}
|
|
isFollowed={{
|
|
loaded: !loading(),
|
|
value: isOwnerSubscribed(author.id),
|
|
}}
|
|
/>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</For>
|
|
<div class="row">
|
|
<div class="col-lg-20 col-xl-18">
|
|
<div class={styles.action}>
|
|
<Show when={!loading() && authorsList().length > 0 && !allLoaded()}>
|
|
<Button value={t('Load more')} onClick={loadMoreAuthors} />
|
|
</Show>
|
|
<Show when={loading() && !allLoaded()}>
|
|
<InlineLoader />
|
|
</Show>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|