2024-06-24 17:50:27 +00:00
|
|
|
import { type RouteDefinition, type RouteSectionProps, createAsync } from '@solidjs/router'
|
2024-07-05 22:45:42 +00:00
|
|
|
import { Show, Suspense, createEffect, createSignal, onMount } from 'solid-js'
|
|
|
|
import { useTopics } from '~/context/topics'
|
|
|
|
import { loadShouts, loadTopics } from '~/graphql/api/public'
|
2024-06-28 07:47:38 +00:00
|
|
|
import { LoadShoutsOptions } from '~/graphql/schema/core.gen'
|
2024-07-05 14:08:12 +00:00
|
|
|
import { byStat } from '~/lib/sortby'
|
2024-06-24 17:50:27 +00:00
|
|
|
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
|
|
|
|
|
2024-07-05 22:45:42 +00:00
|
|
|
const fetchAllTopics = async () => {
|
|
|
|
const allTopicsLoader = loadTopics()
|
|
|
|
return await allTopicsLoader()
|
|
|
|
}
|
|
|
|
|
2024-06-24 17:50:27 +00:00
|
|
|
const fetchHomeTopData = async () => {
|
|
|
|
const topCommentedLoader = loadShouts({
|
|
|
|
filters: { featured: true },
|
2024-06-28 07:47:38 +00:00
|
|
|
order_by: 'comments_stat',
|
|
|
|
limit: 10
|
2024-06-24 17:50:27 +00:00
|
|
|
})
|
|
|
|
|
2024-06-28 07:47:38 +00:00
|
|
|
const daysago = Date.now() - 30 * 24 * 60 * 60 * 1000
|
|
|
|
const after = Math.floor(daysago / 1000)
|
|
|
|
const options: LoadShoutsOptions = {
|
|
|
|
filters: {
|
|
|
|
featured: true,
|
|
|
|
after
|
|
|
|
},
|
|
|
|
order_by: 'likes_stat',
|
|
|
|
limit: 10
|
|
|
|
}
|
|
|
|
const topMonthLoader = loadShouts({ ...options })
|
2024-06-24 17:50:27 +00:00
|
|
|
|
|
|
|
const topRatedLoader = loadShouts({
|
|
|
|
filters: { featured: true },
|
2024-06-28 07:47:38 +00:00
|
|
|
order_by: 'likes_stat',
|
|
|
|
limit: 10
|
2024-06-24 17:50:27 +00:00
|
|
|
})
|
|
|
|
return {
|
|
|
|
topRatedShouts: await topRatedLoader(),
|
2024-06-28 07:47:38 +00:00
|
|
|
topMonthShouts: await topMonthLoader(),
|
|
|
|
topCommentedShouts: await topCommentedLoader()
|
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
|
|
|
})
|
2024-07-05 22:45:42 +00:00
|
|
|
return { ...(await fetchHomeTopData()), featuredShouts: await featuredLoader(), topics: await fetchAllTopics() }
|
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
|
2024-07-05 22:45:42 +00:00
|
|
|
const { addTopics } = useTopics()
|
2024-06-24 17:50:27 +00:00
|
|
|
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) => {
|
2024-07-05 22:45:42 +00:00
|
|
|
const topics = props.data?.topics || await fetchAllTopics()
|
2024-06-24 17:50:27 +00:00
|
|
|
const featuredShoutsLoader = featuredLoader(featuredOffset())
|
2024-06-28 07:47:38 +00:00
|
|
|
const featuredShouts = [
|
|
|
|
...(prev?.featuredShouts || []),
|
|
|
|
...((await featuredShoutsLoader()) || props.data?.featuredShouts || [])
|
|
|
|
]
|
|
|
|
const sortFn = byStat('viewed')
|
|
|
|
const topViewedShouts = featuredShouts?.sort(sortFn) || []
|
|
|
|
const result = {
|
2024-06-24 17:50:27 +00:00
|
|
|
...prev,
|
|
|
|
...props.data,
|
2024-06-28 07:47:38 +00:00
|
|
|
topViewedShouts,
|
2024-07-05 22:45:42 +00:00
|
|
|
featuredShouts,
|
|
|
|
topics
|
2024-06-24 17:50:27 +00:00
|
|
|
}
|
2024-06-28 07:47:38 +00:00
|
|
|
return result
|
2024-06-24 17:50:27 +00:00
|
|
|
})
|
2024-07-05 22:45:42 +00:00
|
|
|
createEffect(() => data()?.topics && addTopics(data()?.topics || []))
|
2024-06-24 17:50:27 +00:00
|
|
|
|
2024-06-28 11:45:25 +00:00
|
|
|
const [canLoadMoreFeatured, setCanLoadMoreFeatured] = createSignal(true)
|
2024-06-24 17:50:27 +00:00
|
|
|
const loadMoreFeatured = async () => {
|
|
|
|
saveScrollPosition()
|
|
|
|
const before = data()?.featuredShouts.length || 0
|
|
|
|
featuredLoader(featuredOffset())
|
|
|
|
setFeaturedOffset((o: number) => o + limit)
|
2024-06-28 11:45:25 +00:00
|
|
|
const after = data()?.featuredShouts.length || 0
|
|
|
|
setTimeout(() => setCanLoadMoreFeatured((_) => before !== after), 1)
|
2024-06-24 17:50:27 +00:00
|
|
|
restoreScrollPosition()
|
|
|
|
}
|
|
|
|
|
2024-06-28 11:45:25 +00:00
|
|
|
onMount(async () => await loadMoreFeatured())
|
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>
|
|
|
|
)
|
|
|
|
}
|