Add pagination on Expo (#441)
* Add pagination on Expo * update Expo load articles method
This commit is contained in:
parent
5334291878
commit
1c94638ce8
|
@ -1,16 +1,14 @@
|
||||||
import { getPagePath } from '@nanostores/router'
|
import { getPagePath } from '@nanostores/router'
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
import { For, Show, createEffect, createMemo, createSignal, on, onCleanup, onMount } from 'solid-js'
|
import { For, Show, createEffect, createSignal, on, onCleanup, onMount } from 'solid-js'
|
||||||
|
|
||||||
import { useLocalize } from '../../../context/localize'
|
import { useLocalize } from '../../../context/localize'
|
||||||
import { apiClient } from '../../../graphql/client/core'
|
import { apiClient } from '../../../graphql/client/core'
|
||||||
import { LoadShoutsFilters, LoadShoutsOptions, Shout } from '../../../graphql/schema/core.gen'
|
import { LoadShoutsFilters, LoadShoutsOptions, Shout } from '../../../graphql/schema/core.gen'
|
||||||
import { LayoutType } from '../../../pages/types'
|
import { LayoutType } from '../../../pages/types'
|
||||||
import { router } from '../../../stores/router'
|
import { router } from '../../../stores/router'
|
||||||
import { loadShouts, resetSortedArticles, useArticlesStore } from '../../../stores/zine/articles'
|
|
||||||
import { getUnixtime } from '../../../utils/getServerDate'
|
import { getUnixtime } from '../../../utils/getServerDate'
|
||||||
import { restoreScrollPosition, saveScrollPosition } from '../../../utils/scroll'
|
import { restoreScrollPosition, saveScrollPosition } from '../../../utils/scroll'
|
||||||
import { splitToPages } from '../../../utils/splitToPages'
|
|
||||||
import { ArticleCard } from '../../Feed/ArticleCard'
|
import { ArticleCard } from '../../Feed/ArticleCard'
|
||||||
import { Button } from '../../_shared/Button'
|
import { Button } from '../../_shared/Button'
|
||||||
import { ConditionalWrapper } from '../../_shared/ConditionalWrapper'
|
import { ConditionalWrapper } from '../../_shared/ConditionalWrapper'
|
||||||
|
@ -28,19 +26,12 @@ export const PRERENDERED_ARTICLES_COUNT = 36
|
||||||
const LOAD_MORE_PAGE_SIZE = 12
|
const LOAD_MORE_PAGE_SIZE = 12
|
||||||
|
|
||||||
export const Expo = (props: Props) => {
|
export const Expo = (props: Props) => {
|
||||||
const [isLoaded, setIsLoaded] = createSignal<boolean>(Boolean(props.shouts))
|
const { t } = useLocalize()
|
||||||
const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false)
|
const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false)
|
||||||
|
|
||||||
const [favoriteTopArticles, setFavoriteTopArticles] = createSignal<Shout[]>([])
|
const [favoriteTopArticles, setFavoriteTopArticles] = createSignal<Shout[]>([])
|
||||||
const [reactedTopMonthArticles, setReactedTopMonthArticles] = createSignal<Shout[]>([])
|
const [reactedTopMonthArticles, setReactedTopMonthArticles] = createSignal<Shout[]>([])
|
||||||
|
const [articlesEndPage, setArticlesEndPage] = createSignal<number>(PRERENDERED_ARTICLES_COUNT)
|
||||||
const { t } = useLocalize()
|
const [expoShouts, setExpoShouts] = createSignal<Shout[]>([])
|
||||||
|
|
||||||
const { sortedArticles } = useArticlesStore({
|
|
||||||
shouts: isLoaded() ? props.shouts : [],
|
|
||||||
layout: props.layout,
|
|
||||||
})
|
|
||||||
|
|
||||||
const getLoadShoutsFilters = (additionalFilters: LoadShoutsFilters = {}): LoadShoutsFilters => {
|
const getLoadShoutsFilters = (additionalFilters: LoadShoutsFilters = {}): LoadShoutsFilters => {
|
||||||
const filters = { ...additionalFilters }
|
const filters = { ...additionalFilters }
|
||||||
|
|
||||||
|
@ -58,15 +49,18 @@ export const Expo = (props: Props) => {
|
||||||
const options: LoadShoutsOptions = {
|
const options: LoadShoutsOptions = {
|
||||||
filters: getLoadShoutsFilters(),
|
filters: getLoadShoutsFilters(),
|
||||||
limit: count,
|
limit: count,
|
||||||
offset: sortedArticles().length,
|
offset: expoShouts().length,
|
||||||
}
|
}
|
||||||
|
|
||||||
options.filters = props.layout
|
options.filters = props.layout
|
||||||
? { layouts: [props.layout] }
|
? { layouts: [props.layout] }
|
||||||
: { layouts: ['audio', 'video', 'image', 'literature'] }
|
: { layouts: ['audio', 'video', 'image', 'literature'] }
|
||||||
|
|
||||||
const { hasMore } = await loadShouts(options)
|
const newShouts = await apiClient.getShouts(options)
|
||||||
|
const hasMore = newShouts?.length !== options.limit + 1 && newShouts?.length !== 0
|
||||||
setIsLoadMoreButtonVisible(hasMore)
|
setIsLoadMoreButtonVisible(hasMore)
|
||||||
|
|
||||||
|
setExpoShouts((prev) => [...prev, ...newShouts])
|
||||||
}
|
}
|
||||||
|
|
||||||
const loadMoreWithoutScrolling = async (count: number) => {
|
const loadMoreWithoutScrolling = async (count: number) => {
|
||||||
|
@ -100,19 +94,7 @@ export const Expo = (props: Props) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
if (isLoaded()) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
loadMore(PRERENDERED_ARTICLES_COUNT + LOAD_MORE_PAGE_SIZE)
|
loadMore(PRERENDERED_ARTICLES_COUNT + LOAD_MORE_PAGE_SIZE)
|
||||||
setIsLoaded(true)
|
|
||||||
})
|
|
||||||
|
|
||||||
onMount(() => {
|
|
||||||
if (sortedArticles().length === PRERENDERED_ARTICLES_COUNT) {
|
|
||||||
loadMore(LOAD_MORE_PAGE_SIZE)
|
|
||||||
}
|
|
||||||
|
|
||||||
loadRandomTopArticles()
|
loadRandomTopArticles()
|
||||||
loadRandomTopMonthArticles()
|
loadRandomTopMonthArticles()
|
||||||
})
|
})
|
||||||
|
@ -121,9 +103,11 @@ export const Expo = (props: Props) => {
|
||||||
on(
|
on(
|
||||||
() => props.layout,
|
() => props.layout,
|
||||||
() => {
|
() => {
|
||||||
resetSortedArticles()
|
setExpoShouts([])
|
||||||
|
setIsLoadMoreButtonVisible(false)
|
||||||
setFavoriteTopArticles([])
|
setFavoriteTopArticles([])
|
||||||
setReactedTopMonthArticles([])
|
setReactedTopMonthArticles([])
|
||||||
|
setArticlesEndPage(PRERENDERED_ARTICLES_COUNT)
|
||||||
loadMore(PRERENDERED_ARTICLES_COUNT + LOAD_MORE_PAGE_SIZE)
|
loadMore(PRERENDERED_ARTICLES_COUNT + LOAD_MORE_PAGE_SIZE)
|
||||||
loadRandomTopArticles()
|
loadRandomTopArticles()
|
||||||
loadRandomTopMonthArticles()
|
loadRandomTopMonthArticles()
|
||||||
|
@ -132,16 +116,17 @@ export const Expo = (props: Props) => {
|
||||||
)
|
)
|
||||||
|
|
||||||
onCleanup(() => {
|
onCleanup(() => {
|
||||||
resetSortedArticles()
|
setExpoShouts([])
|
||||||
})
|
})
|
||||||
|
|
||||||
const handleLoadMoreClick = () => {
|
const handleLoadMoreClick = () => {
|
||||||
loadMoreWithoutScrolling(LOAD_MORE_PAGE_SIZE)
|
loadMoreWithoutScrolling(LOAD_MORE_PAGE_SIZE)
|
||||||
|
setArticlesEndPage((prev) => prev + LOAD_MORE_PAGE_SIZE)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class={styles.Expo}>
|
<div class={styles.Expo}>
|
||||||
<Show when={sortedArticles()?.length > 0} fallback={<Loading />}>
|
<Show when={expoShouts().length > 0} fallback={<Loading />}>
|
||||||
<div class="wide-container">
|
<div class="wide-container">
|
||||||
<ul class={clsx('view-switcher')}>
|
<ul class={clsx('view-switcher')}>
|
||||||
<li class={clsx({ 'view-switcher__item--selected': !props.layout })}>
|
<li class={clsx({ 'view-switcher__item--selected': !props.layout })}>
|
||||||
|
@ -194,7 +179,7 @@ export const Expo = (props: Props) => {
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<For each={sortedArticles().slice(0, LOAD_MORE_PAGE_SIZE)}>
|
<For each={expoShouts()?.slice(0, LOAD_MORE_PAGE_SIZE)}>
|
||||||
{(shout) => (
|
{(shout) => (
|
||||||
<div class="col-md-6 mt-md-5 col-sm-8 mt-sm-3">
|
<div class="col-md-6 mt-md-5 col-sm-8 mt-sm-3">
|
||||||
<ArticleCard
|
<ArticleCard
|
||||||
|
@ -209,7 +194,7 @@ export const Expo = (props: Props) => {
|
||||||
<Show when={reactedTopMonthArticles()?.length > 0} keyed={true}>
|
<Show when={reactedTopMonthArticles()?.length > 0} keyed={true}>
|
||||||
<ArticleCardSwiper title={t('Top month articles')} slides={reactedTopMonthArticles()} />
|
<ArticleCardSwiper title={t('Top month articles')} slides={reactedTopMonthArticles()} />
|
||||||
</Show>
|
</Show>
|
||||||
<For each={sortedArticles().slice(LOAD_MORE_PAGE_SIZE, LOAD_MORE_PAGE_SIZE * 2)}>
|
<For each={expoShouts().slice(LOAD_MORE_PAGE_SIZE, LOAD_MORE_PAGE_SIZE * 2)}>
|
||||||
{(shout) => (
|
{(shout) => (
|
||||||
<div class="col-md-6 mt-md-5 col-sm-8 mt-sm-3">
|
<div class="col-md-6 mt-md-5 col-sm-8 mt-sm-3">
|
||||||
<ArticleCard
|
<ArticleCard
|
||||||
|
@ -224,7 +209,7 @@ export const Expo = (props: Props) => {
|
||||||
<Show when={favoriteTopArticles()?.length > 0} keyed={true}>
|
<Show when={favoriteTopArticles()?.length > 0} keyed={true}>
|
||||||
<ArticleCardSwiper title={t('Favorite')} slides={favoriteTopArticles()} />
|
<ArticleCardSwiper title={t('Favorite')} slides={favoriteTopArticles()} />
|
||||||
</Show>
|
</Show>
|
||||||
<For each={sortedArticles().slice(LOAD_MORE_PAGE_SIZE * 2)}>
|
<For each={expoShouts().slice(LOAD_MORE_PAGE_SIZE * 2, articlesEndPage())}>
|
||||||
{(shout) => (
|
{(shout) => (
|
||||||
<div class="col-md-6 mt-md-5 col-sm-8 mt-sm-3">
|
<div class="col-md-6 mt-md-5 col-sm-8 mt-sm-3">
|
||||||
<ArticleCard
|
<ArticleCard
|
||||||
|
|
Loading…
Reference in New Issue
Block a user