144 lines
4.6 KiB
TypeScript
144 lines
4.6 KiB
TypeScript
import { RouteSectionProps, createAsync, useParams, useSearchParams } from '@solidjs/router'
|
|
import { Client } from '@urql/core'
|
|
import { Show, createEffect, createSignal } from 'solid-js'
|
|
import { Feed } from '~/components/Views/Feed'
|
|
import { PageLayout } from '~/components/_shared/PageLayout'
|
|
import { useGraphQL } from '~/context/graphql'
|
|
import { useLocalize } from '~/context/localize'
|
|
import { ReactionsProvider } from '~/context/reactions'
|
|
import { useSession } from '~/context/session'
|
|
import { LoadShoutsOptions, Shout } from '~/graphql/schema/core.gen'
|
|
import {
|
|
loadBookmarkedShouts,
|
|
loadCoauthoredShouts,
|
|
loadDiscussedShouts,
|
|
loadFollowedShouts,
|
|
loadUnratedShouts
|
|
} from '~/lib/api/private'
|
|
import { loadShouts } from '~/lib/api/public'
|
|
import { SHOUTS_PER_PAGE } from '../(home)'
|
|
|
|
export type FeedPeriod = 'week' | 'month' | 'year'
|
|
|
|
export type PeriodItem = {
|
|
value: FeedPeriod
|
|
title: string
|
|
}
|
|
|
|
export type FeedSearchParams = {
|
|
by: 'after' | 'likes' | 'last_comment'
|
|
period: FeedPeriod
|
|
}
|
|
|
|
const getFromDate = (period: FeedPeriod): number => {
|
|
const now = new Date()
|
|
let d: Date = now
|
|
switch (period) {
|
|
case 'week': {
|
|
d = new Date(now.setDate(now.getDate() - 7))
|
|
break
|
|
}
|
|
case 'month': {
|
|
d = new Date(now.setMonth(now.getMonth() - 1))
|
|
break
|
|
}
|
|
case 'year': {
|
|
d = new Date(now.setFullYear(now.getFullYear() - 1))
|
|
break
|
|
}
|
|
}
|
|
return Math.floor(d.getTime() / 1000)
|
|
}
|
|
|
|
const fetchPublishedShouts = async (offset?: number, _client?: Client) => {
|
|
const shoutsLoader = loadShouts({ filters: { featured: undefined }, limit: SHOUTS_PER_PAGE, offset })
|
|
return await shoutsLoader()
|
|
}
|
|
|
|
const fetchBookmarkedShouts = async (offset?: number, client?: Client) => {
|
|
const shoutsLoader = loadBookmarkedShouts(client, { limit: SHOUTS_PER_PAGE, offset })
|
|
return await shoutsLoader()
|
|
}
|
|
|
|
const fetchUnratedShouts = async (offset?: number, client?: Client) => {
|
|
const shoutsLoader = loadUnratedShouts(client, { limit: SHOUTS_PER_PAGE, offset })
|
|
return await shoutsLoader()
|
|
}
|
|
|
|
const fetchFollowedShouts = async (offset?: number, client?: Client) => {
|
|
const shoutsLoader = loadFollowedShouts(client, { limit: SHOUTS_PER_PAGE, offset })
|
|
return await shoutsLoader()
|
|
}
|
|
|
|
const fetchDiscussedShouts = async (offset?: number, client?: Client) => {
|
|
const shoutsLoader = loadDiscussedShouts(client, { limit: SHOUTS_PER_PAGE, offset })
|
|
return await shoutsLoader()
|
|
}
|
|
|
|
const fetchCoauthoredShouts = async (offset?: number, client?: Client) => {
|
|
const shoutsLoader = loadCoauthoredShouts(client, { limit: SHOUTS_PER_PAGE, offset })
|
|
return await shoutsLoader()
|
|
}
|
|
|
|
const fetchersByMode = {
|
|
followed: fetchFollowedShouts,
|
|
bookmarked: fetchBookmarkedShouts,
|
|
discussed: fetchDiscussedShouts,
|
|
coauthored: fetchCoauthoredShouts,
|
|
unrated: fetchUnratedShouts
|
|
}
|
|
|
|
export const route = {
|
|
load: async ({ location: { query } }: RouteSectionProps<{ articles: Shout[] }>) => {
|
|
const offset: number = Number.parseInt(query.offset, 10)
|
|
const result = await fetchPublishedShouts(offset)
|
|
return result
|
|
}
|
|
}
|
|
|
|
export const FeedPage = (props: RouteSectionProps<Shout[]>) => {
|
|
const [searchParams] = useSearchParams<FeedSearchParams>()
|
|
const { t } = useLocalize()
|
|
const params = useParams()
|
|
const client = useGraphQL()
|
|
const { session } = useSession()
|
|
const [offset, setOffset] = createSignal<number>(0)
|
|
const shouts = createAsync(async () => ({ ...props.data }) || (await loadMore()))
|
|
const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal<boolean>(true)
|
|
const loadMore = async () => {
|
|
const newOffset = offset() + SHOUTS_PER_PAGE
|
|
setOffset(newOffset)
|
|
const options: LoadShoutsOptions = {
|
|
limit: SHOUTS_PER_PAGE,
|
|
offset: newOffset,
|
|
order_by: searchParams?.by
|
|
}
|
|
|
|
if (searchParams?.by === 'after') {
|
|
const period = searchParams?.by || 'month'
|
|
options.filters = { after: getFromDate(period as FeedPeriod) }
|
|
}
|
|
if (!session()) return await fetchPublishedShouts(newOffset)
|
|
const fetcher = fetchersByMode[params.feed as keyof typeof fetchersByMode]
|
|
if (!fetcher) return await fetchPublishedShouts(newOffset)
|
|
return await fetcher(newOffset, client)
|
|
}
|
|
createEffect(() => setIsLoadMoreButtonVisible(offset() < (shouts()?.length || 0)))
|
|
return (
|
|
<PageLayout title={t('Feed')}>
|
|
<ReactionsProvider>
|
|
<Feed shouts={shouts() || []} />
|
|
</ReactionsProvider>
|
|
<Show when={isLoadMoreButtonVisible()}>
|
|
<p class="load-more-container">
|
|
<button class="button" onClick={loadMore}>
|
|
{t('Load more')}
|
|
</button>
|
|
</p>
|
|
</Show>
|
|
</PageLayout>
|
|
)
|
|
}
|
|
|
|
export const Page = FeedPage
|