loadmore+feed+my

This commit is contained in:
Untone 2024-07-15 23:56:40 +03:00
parent 4fe2768329
commit 8cce8d897e
4 changed files with 50 additions and 29 deletions

View File

@ -8,7 +8,6 @@ import { InviteMembers } from '~/components/_shared/InviteMembers'
import { Loading } from '~/components/_shared/Loading' import { Loading } from '~/components/_shared/Loading'
import { ShareModal } from '~/components/_shared/ShareModal' import { ShareModal } from '~/components/_shared/ShareModal'
import { useAuthors } from '~/context/authors' import { useAuthors } from '~/context/authors'
import { useFeed } from '~/context/feed'
import { useGraphQL } from '~/context/graphql' import { useGraphQL } from '~/context/graphql'
import { useLocalize } from '~/context/localize' import { useLocalize } from '~/context/localize'
import { useReactions } from '~/context/reactions' import { useReactions } from '~/context/reactions'
@ -35,8 +34,9 @@ export const FEED_PAGE_SIZE = 20
export type PeriodType = 'week' | 'month' | 'year' export type PeriodType = 'week' | 'month' | 'year'
export type FeedProps = { export type FeedProps = {
shouts?: Shout[] shouts: Shout[]
mode?: '' | 'likes' | 'hot' mode?: 'followed' | 'discussed' | 'coauthored' | 'unrated'
order?: '' | 'likes' | 'hot'
} }
export const FeedView = (props: FeedProps) => { export const FeedView = (props: FeedProps) => {
@ -54,7 +54,6 @@ export const FeedView = (props: FeedProps) => {
const [isLoading, setIsLoading] = createSignal(false) const [isLoading, setIsLoading] = createSignal(false)
const [isRightColumnLoaded, setIsRightColumnLoaded] = createSignal(false) const [isRightColumnLoaded, setIsRightColumnLoaded] = createSignal(false)
const { session } = useSession() const { session } = useSession()
const { feed, setFeed } = useFeed()
const { loadReactionsBy } = useReactions() const { loadReactionsBy } = useReactions()
const { topTopics } = useTopics() const { topTopics } = useTopics()
const { topAuthors } = useAuthors() const { topAuthors } = useAuthors()
@ -68,13 +67,13 @@ export const FeedView = (props: FeedProps) => {
setTopComments(comments.sort(byCreated).reverse()) setTopComments(comments.sort(byCreated).reverse())
} }
// post-load
createEffect( createEffect(
on( on(
feed, () => props.shouts,
(sss?: Shout[]) => { (sss?: Shout[]) => {
if (sss && Array.isArray(sss)) { if (sss && Array.isArray(sss)) {
setIsLoading(true) setIsLoading(true)
setFeed((prev) => [...prev, ...sss])
Promise.all([ Promise.all([
loadTopComments(), loadTopComments(),
loadReactionsBy({ by: { shouts: sss.map((s: Shout) => s.slug) } }) loadReactionsBy({ by: { shouts: sss.map((s: Shout) => s.slug) } })
@ -107,15 +106,15 @@ export const FeedView = (props: FeedProps) => {
<Placeholder type={loc?.pathname} mode="feed" /> <Placeholder type={loc?.pathname} mode="feed" />
</Show> </Show>
<Show when={(session() || loc?.pathname === 'feed') && feed()?.length}> <Show when={(session() || loc?.pathname === 'feed') && props.shouts?.length}>
<div class={styles.filtersContainer}> <div class={styles.filtersContainer}>
<ul class={clsx('view-switcher', styles.feedFilter)}> <ul class={clsx('view-switcher', styles.feedFilter)}>
<li class={clsx({ 'view-switcher__item--selected': !props.mode })}> <li class={clsx({ 'view-switcher__item--selected': !props.order })}>
<A href={loc.pathname}>{t('Recent')}</A> <A href={loc.pathname}>{t('Recent')}</A>
</li> </li>
<li <li
class={clsx({ class={clsx({
'view-switcher__item--selected': props.mode === 'likes' 'view-switcher__item--selected': props.order === 'likes'
})} })}
> >
<A class="link" href={'/feed/likes'}> <A class="link" href={'/feed/likes'}>
@ -124,7 +123,7 @@ export const FeedView = (props: FeedProps) => {
</li> </li>
<li <li
class={clsx({ class={clsx({
'view-switcher__item--selected': props.mode === 'hot' 'view-switcher__item--selected': props.order === 'hot'
})} })}
> >
<A class="link" href={'/feed/hot'}> <A class="link" href={'/feed/hot'}>
@ -153,8 +152,8 @@ export const FeedView = (props: FeedProps) => {
</div> </div>
<Show when={!isLoading()} fallback={<Loading />}> <Show when={!isLoading()} fallback={<Loading />}>
<Show when={(feed() || []).length > 0}> <Show when={(props.shouts || []).length > 0}>
<For each={(feed() || []).slice(0, 4)}> <For each={(props.shouts || []).slice(0, 4)}>
{(article) => ( {(article) => (
<ArticleCard <ArticleCard
onShare={(shared) => handleShare(shared)} onShare={(shared) => handleShare(shared)}
@ -186,7 +185,7 @@ export const FeedView = (props: FeedProps) => {
</ul> </ul>
</div> </div>
<For each={(feed() || []).slice(4)}> <For each={(props.shouts || []).slice(4)}>
{(article) => ( {(article) => (
<ArticleCard article={article} settings={{ isFeedMode: true }} desktopCoverSize="M" /> <ArticleCard article={article} settings={{ isFeedMode: true }} desktopCoverSize="M" />
)} )}

View File

@ -113,7 +113,7 @@ export default function HomePage(props: RouteSectionProps<HomeViewProps>) {
<Show when={(featuredFeed() || []).length > 0} fallback={<Loading />}> <Show when={(featuredFeed() || []).length > 0} fallback={<Loading />}>
<LoadMoreWrapper loadFunction={loadMoreFeatured} pageSize={SHOUTS_PER_PAGE}> <LoadMoreWrapper loadFunction={loadMoreFeatured} pageSize={SHOUTS_PER_PAGE}>
<HomeView <HomeView
featuredShouts={featuredFeed() || shouts() as Shout[]} featuredShouts={featuredFeed() || (shouts() as Shout[])}
topMonthShouts={topMonthFeed() as Shout[]} topMonthShouts={topMonthFeed() as Shout[]}
topViewedShouts={topViewedFeed() as Shout[]} topViewedShouts={topViewedFeed() as Shout[]}
topRatedShouts={topRatedFeed() as Shout[]} topRatedShouts={topRatedFeed() as Shout[]}

View File

@ -1,8 +1,9 @@
import { RouteSectionProps, createAsync, useSearchParams } from '@solidjs/router' import { RouteSectionProps, createAsync, useSearchParams } from '@solidjs/router'
import { Client } from '@urql/core' import { Client } from '@urql/core'
import { createEffect } from 'solid-js' import { createEffect, createMemo } from 'solid-js'
import { AUTHORS_PER_PAGE } from '~/components/Views/AllAuthors/AllAuthors' import { AUTHORS_PER_PAGE } from '~/components/Views/AllAuthors/AllAuthors'
import { Feed } from '~/components/Views/Feed' import { Feed } from '~/components/Views/Feed'
import { FeedProps } from '~/components/Views/Feed/Feed'
import { LoadMoreItems, LoadMoreWrapper } from '~/components/_shared/LoadMoreWrapper' import { LoadMoreItems, LoadMoreWrapper } from '~/components/_shared/LoadMoreWrapper'
import { PageLayout } from '~/components/_shared/PageLayout' import { PageLayout } from '~/components/_shared/PageLayout'
import { useFeed } from '~/context/feed' import { useFeed } from '~/context/feed'
@ -60,7 +61,7 @@ export const route = {
export default (props: RouteSectionProps<{ shouts: Shout[]; topics: Topic[] }>) => { export default (props: RouteSectionProps<{ shouts: Shout[]; topics: Topic[] }>) => {
const [searchParams] = useSearchParams<FeedSearchParams>() // ?period=month const [searchParams] = useSearchParams<FeedSearchParams>() // ?period=month
const { t } = useLocalize() const { t } = useLocalize()
const { setFeed } = useFeed() const { feed, setFeed } = useFeed()
// preload all topics // preload all topics
const { addTopics, sortedTopics } = useTopics() const { addTopics, sortedTopics } = useTopics()
@ -106,6 +107,17 @@ export default (props: RouteSectionProps<{ shouts: Shout[]; topics: Topic[] }>)
return (await loadMoreFeed()) as Shout[] return (await loadMoreFeed()) as Shout[]
}) })
const order = createMemo(() => {
const paramOrderPattern = /^(hot|likes)$/
return (
(paramOrderPattern.test(props.params.order)
? props.params.order === 'hot'
? 'last_comment'
: props.params.order
: 'created_at') || 'created_at'
)
})
return ( return (
<PageLayout <PageLayout
withPadding={true} withPadding={true}
@ -115,7 +127,7 @@ export default (props: RouteSectionProps<{ shouts: Shout[]; topics: Topic[] }>)
> >
<LoadMoreWrapper loadFunction={loadMoreFeed} pageSize={AUTHORS_PER_PAGE}> <LoadMoreWrapper loadFunction={loadMoreFeed} pageSize={AUTHORS_PER_PAGE}>
<ReactionsProvider> <ReactionsProvider>
<Feed /> <Feed shouts={feed() || (shouts() as Shout[])} order={order() as FeedProps['order']} />
</ReactionsProvider> </ReactionsProvider>
</LoadMoreWrapper> </LoadMoreWrapper>
</PageLayout> </PageLayout>

View File

@ -1,7 +1,8 @@
import { RouteSectionProps, useSearchParams } from '@solidjs/router' import { RouteSectionProps, useSearchParams } from '@solidjs/router'
import { createEffect } from 'solid-js' import { createEffect, createMemo } from 'solid-js'
import { AUTHORS_PER_PAGE } from '~/components/Views/AllAuthors/AllAuthors' import { AUTHORS_PER_PAGE } from '~/components/Views/AllAuthors/AllAuthors'
import { Feed } from '~/components/Views/Feed' import { Feed } from '~/components/Views/Feed'
import { FeedProps } from '~/components/Views/Feed/Feed'
import { LoadMoreItems, LoadMoreWrapper } from '~/components/_shared/LoadMoreWrapper' import { LoadMoreItems, LoadMoreWrapper } from '~/components/_shared/LoadMoreWrapper'
import { PageLayout } from '~/components/_shared/PageLayout' import { PageLayout } from '~/components/_shared/PageLayout'
import { useFeed } from '~/context/feed' import { useFeed } from '~/context/feed'
@ -52,7 +53,7 @@ const getFromDate = (period: FeedPeriod): number => {
export default (props: RouteSectionProps<{ shouts: Shout[]; topics: Topic[] }>) => { export default (props: RouteSectionProps<{ shouts: Shout[]; topics: Topic[] }>) => {
const [searchParams] = useSearchParams<FeedSearchParams>() // ?period=month const [searchParams] = useSearchParams<FeedSearchParams>() // ?period=month
const { t } = useLocalize() const { t } = useLocalize()
const { setFeed } = useFeed() const { setFeed, feed } = useFeed()
// TODO: use const { requireAuthentication } = useSession() // TODO: use const { requireAuthentication } = useSession()
const client = useGraphQL() const client = useGraphQL()
@ -62,27 +63,32 @@ export default (props: RouteSectionProps<{ shouts: Shout[]; topics: Topic[] }>)
!sortedTopics() && props.data.topics && addTopics(props.data.topics) !sortedTopics() && props.data.topics && addTopics(props.data.topics)
}) })
// load more my feed // /feed/my/:mode:
const loadMoreMyFeed = async (offset?: number) => { const mode = createMemo(() => {
// /feed/my/:mode:
const paramModePattern = /^(followed|discussed|liked|coauthored|unrated)$/ const paramModePattern = /^(followed|discussed|liked|coauthored|unrated)$/
const mode = return props.params.mode && paramModePattern.test(props.params.mode) ? props.params.mode : 'followed'
props.params.mode && paramModePattern.test(props.params.mode) ? props.params.mode : 'followed' })
const gqlHandler = feeds[mode as keyof typeof feeds]
// /feed/my/:mode:/:order: - select order setting const order = createMemo(() => {
const paramOrderPattern = /^(hot|likes)$/ const paramOrderPattern = /^(hot|likes)$/
const order = return (
(paramOrderPattern.test(props.params.order) (paramOrderPattern.test(props.params.order)
? props.params.order === 'hot' ? props.params.order === 'hot'
? 'last_comment' ? 'last_comment'
: props.params.order : props.params.order
: 'created_at') || 'created_at' : 'created_at') || 'created_at'
)
})
// load more my feed
const loadMoreMyFeed = async (offset?: number) => {
const gqlHandler = feeds[mode() as keyof typeof feeds]
// /feed/my/:mode:/:order: - select order setting
const options: LoadShoutsOptions = { const options: LoadShoutsOptions = {
limit: 20, limit: 20,
offset, offset,
order_by: order order_by: order()
} }
// ?period=month - time period filter // ?period=month - time period filter
@ -106,7 +112,11 @@ export default (props: RouteSectionProps<{ shouts: Shout[]; topics: Topic[] }>)
> >
<LoadMoreWrapper loadFunction={loadMoreMyFeed} pageSize={AUTHORS_PER_PAGE}> <LoadMoreWrapper loadFunction={loadMoreMyFeed} pageSize={AUTHORS_PER_PAGE}>
<ReactionsProvider> <ReactionsProvider>
<Feed /> <Feed
shouts={feed() || []}
mode={(mode() || 'followed') as FeedProps['mode']}
order={order() as FeedProps['order']}
/>
</ReactionsProvider> </ReactionsProvider>
</LoadMoreWrapper> </LoadMoreWrapper>
</PageLayout> </PageLayout>