webapp/src/routes/(home).tsx

120 lines
3.4 KiB
TypeScript
Raw Normal View History

2024-06-24 17:50:27 +00:00
import { type RouteDefinition, type RouteSectionProps, createAsync } from '@solidjs/router'
import { Show, Suspense, createEffect, createSignal, on, onMount } from 'solid-js'
import { loadShouts } from '~/lib/api'
import { restoreScrollPosition, saveScrollPosition } from '~/utils/scroll'
import { HomeView, HomeViewProps } from '../components/Views/Home'
import { Loading } from '../components/_shared/Loading'
import { PageLayout } from '../components/_shared/PageLayout'
import { useLocalize } from '../context/localize'
import { ReactionsProvider } from '../context/reactions'
export const SHOUTS_PER_PAGE = 20
const fetchHomeTopData = async () => {
const limit = 20
const topCommentedLoader = loadShouts({
filters: { featured: true },
2024-06-26 08:22:05 +00:00
limit
2024-06-24 17:50:27 +00:00
})
const topMonthLoader = loadShouts({
filters: { featured: true },
2024-06-26 08:22:05 +00:00
limit
2024-06-24 17:50:27 +00:00
})
const topViewedLoader = loadShouts({
filters: { featured: true },
2024-06-26 08:22:05 +00:00
limit
2024-06-24 17:50:27 +00:00
})
const topRatedLoader = loadShouts({
filters: { featured: true },
2024-06-26 08:22:05 +00:00
limit
2024-06-24 17:50:27 +00:00
})
return {
topCommentedShouts: await topCommentedLoader(),
topMonthShouts: await topMonthLoader(),
topRatedShouts: await topRatedLoader(),
2024-06-26 08:22:05 +00:00
topViewedShouts: await topViewedLoader()
2024-06-24 17:50:27 +00:00
} as Partial<HomeViewProps>
}
export const route = {
load: async () => {
const limit = 20
const featuredLoader = loadShouts({
filters: { featured: true },
2024-06-26 08:22:05 +00:00
limit
2024-06-24 17:50:27 +00:00
})
return { ...(await fetchHomeTopData()), featuredShouts: await featuredLoader() }
2024-06-26 08:22:05 +00:00
}
2024-06-24 17:50:27 +00:00
} satisfies RouteDefinition
export default function HomePage(props: RouteSectionProps<HomeViewProps>) {
const limit = 20
const { t } = useLocalize()
const [featuredOffset, setFeaturedOffset] = createSignal<number>(0)
const featuredLoader = (offset?: number) => {
const result = loadShouts({
filters: { featured: true },
limit,
2024-06-26 08:22:05 +00:00
offset
2024-06-24 17:50:27 +00:00
})
return result
}
// async ssr-friendly router-level cached data source
const data = createAsync(async (prev?: HomeViewProps) => {
const featuredShoutsLoader = featuredLoader(featuredOffset())
const featuredShouts = await featuredShoutsLoader()
return {
...prev,
...props.data,
2024-06-26 08:22:05 +00:00
featuredShouts: featuredShouts || prev?.featuredShouts || props.data?.featuredShouts
2024-06-24 17:50:27 +00:00
}
})
const [canLoadMoreFeatured, setCanLoadMoreFeatured] = createSignal(false)
const loadMoreFeatured = async () => {
saveScrollPosition()
const before = data()?.featuredShouts.length || 0
featuredLoader(featuredOffset())
const after = data()?.featuredShouts.length || 0
setCanLoadMoreFeatured((_) => before !== after)
setFeaturedOffset((o: number) => o + limit)
restoreScrollPosition()
}
onMount(loadMoreFeatured)
// Re-run the loader whenever the featured offset changes
createEffect(
on(
featuredOffset,
(o: number) => {
featuredLoader(o) // using fresh offset by itself
},
2024-06-26 08:22:05 +00:00
{ defer: true }
)
2024-06-24 17:50:27 +00:00
)
return (
<PageLayout withPadding={true} title={t('Discours')}>
<ReactionsProvider>
<Suspense fallback={<Loading />}>
<HomeView {...(data() as HomeViewProps)} />
<Show when={canLoadMoreFeatured()}>
<p class="load-more-container">
<button class="button" onClick={loadMoreFeatured}>
{t('Load more')}
</button>
</p>
</Show>
</Suspense>
</ReactionsProvider>
</PageLayout>
)
}