topic+author-loadmore-fix

This commit is contained in:
Untone 2024-08-28 16:10:00 +03:00
parent 22f44ee0ec
commit f808bd2394
4 changed files with 93 additions and 105 deletions

View File

@ -1,6 +1,6 @@
import { A, useLocation, useParams } from '@solidjs/router'
import { clsx } from 'clsx'
import { For, Match, Show, Switch, createEffect, createMemo, createSignal, on } from 'solid-js'
import { For, Match, Show, Switch, createEffect, createMemo, createSignal } from 'solid-js'
import { Loading } from '~/components/_shared/Loading'
import { coreApiUrl } from '~/config'
import { useAuthors } from '~/context/authors'
@ -12,7 +12,6 @@ import getAuthorFollowersQuery from '~/graphql/query/core/author-followers'
import getAuthorFollowsQuery from '~/graphql/query/core/author-follows'
import type { Author, Reaction, Shout, Topic } from '~/graphql/schema/core.gen'
import { byCreated } from '~/lib/sort'
import { paginate } from '~/utils/paginate'
import stylesArticle from '../../Article/Article.module.scss'
import { Comment } from '../../Article/Comment'
import { AuthorCard } from '../../Author/AuthorCard'
@ -25,20 +24,19 @@ import styles from './Author.module.scss'
type AuthorViewProps = {
authorSlug: string
selectedTab: string
shouts?: Shout[]
shouts: Shout[]
author?: Author
}
export const PRERENDERED_ARTICLES_COUNT = 12
const LOAD_MORE_PAGE_SIZE = 9
// const LOAD_MORE_PAGE_SIZE = 9
export const AuthorView = (props: AuthorViewProps) => {
// contexts
const { t } = useLocalize()
const loc = useLocation()
const params = useParams()
const [currentTab, setCurrentTab] = createSignal<string>(props.selectedTab)
const [currentTab, setCurrentTab] = createSignal<string>(params.tab)
const { session } = useSession()
const client = createMemo(() => graphqlClientCreate(coreApiUrl, session()?.access_token))
@ -56,21 +54,11 @@ export const AuthorView = (props: AuthorViewProps) => {
// derivatives
const me = createMemo<Author>(() => session()?.user?.app_data?.profile as Author)
const pages = createMemo<Shout[][]>(() =>
paginate((props.shouts || []).slice(1), PRERENDERED_ARTICLES_COUNT, LOAD_MORE_PAGE_SIZE)
)
// Переход по табам
createEffect(
on(
() => params.tab,
(tab: string) => {
// Обновляем текущую вкладку
setCurrentTab(tab || '')
},
{}
)
)
createEffect(() => {
setCurrentTab(params.tab)
})
// Объединенный эффект для загрузки автора и его подписок
createEffect(async () => {
@ -171,7 +159,6 @@ export const AuthorView = (props: AuthorViewProps) => {
</div>
<Switch>
<Match when={currentTab() === 'about'}>
<div class="wide-container">
<div class="row">
@ -198,7 +185,6 @@ export const AuthorView = (props: AuthorViewProps) => {
</Match>
<Match when={currentTab() === 'comments'}>
<Show when={me()?.slug === props.authorSlug && !me().stat?.comments}>
<div class="wide-container">
<Placeholder type={loc?.pathname} mode="profile" />
@ -232,36 +218,29 @@ export const AuthorView = (props: AuthorViewProps) => {
</div>
</Show>
<Show when={Array.isArray(props.shouts) && props.shouts.length > 0 && props.shouts[0]}>
<Row1 article={props.shouts?.[0] as Shout} noauthor={true} nodate={true} />
<Show when={props.shouts && props.shouts.length > 1}>
<Switch>
<Match when={props.shouts && props.shouts.length === 2}>
<Row2 articles={props.shouts as Shout[]} isEqual={true} noauthor={true} nodate={true} />
</Match>
<Match when={props.shouts && props.shouts.length === 3}>
<Row3 articles={props.shouts as Shout[]} noauthor={true} nodate={true} />
</Match>
<Match when={props.shouts && props.shouts.length > 3}>
<For each={pages()}>
{(page) => (
<>
<Row1 article={page[0]} noauthor={true} nodate={true} />
<Row2 articles={page.slice(1, 3)} isEqual={true} noauthor={true} />
<Row1 article={page[3]} noauthor={true} nodate={true} />
<Row2 articles={page.slice(4, 6)} isEqual={true} noauthor={true} />
<Row1 article={page[6]} noauthor={true} nodate={true} />
<Row2 articles={page.slice(7, 9)} isEqual={true} noauthor={true} />
</>
)}
</For>
</Match>
</Switch>
</Show>
<Show when={Array.isArray(props.shouts) && props.shouts.length > 0}>
<For each={props.shouts.filter((_, i) => i % 3 === 0)}>
{(_shout, index) => {
const articles = props.shouts.slice(index() * 3, index() * 3 + 3);
return (
<>
<Switch>
<Match when={articles.length === 1}>
<Row1 article={articles[0]} noauthor={true} nodate={true} />
</Match>
<Match when={articles.length === 2}>
<Row2 articles={articles} noauthor={true} nodate={true} isEqual={true} />
</Match>
<Match when={articles.length === 3}>
<Row3 articles={articles} noauthor={true} nodate={true} />
</Match>
</Switch>
</>
);
}}
</For>
</Show>
</Match>
</Switch>
</div>
)

View File

@ -1,6 +1,6 @@
import { useSearchParams } from '@solidjs/router'
import { clsx } from 'clsx'
import { For, Show, Suspense, createEffect, createMemo, createSignal, on } from 'solid-js'
import { For, Match, Show, Suspense, Switch, createEffect, createSignal, on } from 'solid-js'
import { useAuthors } from '~/context/authors'
import { useFeed } from '~/context/feed'
import { useLocalize } from '~/context/localize'
@ -9,7 +9,6 @@ import { loadAuthors, loadFollowersByTopic, loadShouts } from '~/graphql/api/pub
import { Author, AuthorsBy, LoadShoutsOptions, Shout, Topic } from '~/graphql/schema/core.gen'
import { SHOUTS_PER_PAGE } from '~/routes/(main)'
import { getUnixtime } from '~/utils/date'
import { paginate } from '~/utils/paginate'
import { restoreScrollPosition, saveScrollPosition } from '~/utils/scroll'
import styles from '../../styles/Topic.module.scss'
import { Beside } from '../Feed/Beside'
@ -21,7 +20,6 @@ import { LoadMoreItems, LoadMoreWrapper } from '../_shared/LoadMoreWrapper'
import { Loading } from '../_shared/Loading'
import { ArticleCardSwiper } from '../_shared/SolidSwiper/ArticleCardSwiper'
// FIXME: should be 'last_comment' and 'comments_stat' or just one?
export type TopicFeedSortBy = 'comments' | '' | 'recent' | 'viewed' | 'rating' | 'last_comment'
interface Props {
@ -33,7 +31,7 @@ interface Props {
}
export const PRERENDERED_ARTICLES_COUNT = 28
const LOAD_MORE_PAGE_SIZE = 9 // Row3 + Row3 + Row3
// const LOAD_MORE_PAGE_SIZE = 9 // Row3 + Row3 + Row3
export const TopicView = (props: Props) => {
const { t } = useLocalize()
@ -49,13 +47,13 @@ export const TopicView = (props: Props) => {
// TODO: filter + sort
const [sortedFeed, setSortedFeed] = createSignal([] as Shout[])
createEffect(on(([feedByTopic, () => props.topicSlug, topicEntities]), ([feed, slug, ttt]) => {
if (Object.values(ttt).length === 0) return
const sss = (feed[slug] || []) as Shout[]
sss && setSortedFeed(sss)
console.debug('topic slug loaded', slug)
const tpc = ttt[slug]
console.debug('topics loaded', ttt)
tpc && setTopic(tpc)
if (Object.values(ttt).length === 0) return
const sss = (feed[slug] || []) as Shout[]
sss && setSortedFeed(sss)
console.debug('topic slug loaded', slug)
const tpc = ttt[slug]
console.debug('topics loaded', ttt)
tpc && setTopic(tpc)
}, {}))
const loadTopicFollowers = async () => {
@ -104,12 +102,12 @@ export const TopicView = (props: Props) => {
// второй этап начальной загрузки данных
createEffect(on(topic, (tpc) => {
console.debug('topic loaded', tpc)
if (!tpc) return
loadFavoriteTopArticles()
loadReactedTopMonthArticles()
loadTopicAuthors()
loadTopicFollowers()
console.debug('topic loaded', tpc)
if (!tpc) return
loadFavoriteTopArticles()
loadReactedTopMonthArticles()
loadTopicAuthors()
loadTopicFollowers()
}, { defer: true }))
// дозагрузка
@ -137,9 +135,6 @@ export const TopicView = (props: Props) => {
})
*/
const pages = createMemo<Shout[][]>(() =>
paginate(sortedFeed(), PRERENDERED_ARTICLES_COUNT, LOAD_MORE_PAGE_SIZE)
)
return (
<div class={styles.topicPage}>
<Suspense fallback={<Loading />}>
@ -223,15 +218,26 @@ export const TopicView = (props: Props) => {
</Show>
<LoadMoreWrapper loadFunction={loadMore} pageSize={SHOUTS_PER_PAGE}>
<For each={pages()}>
{(page) => (
<For each={sortedFeed().slice(19).filter((_, i) => i % 3 === 0)}>
{(_shout, index) => {
const articles = sortedFeed().slice(19).slice(index() * 3, index() * 3 + 3);
return (
<>
<Row3 articles={page.slice(0, 3)} />
<Row3 articles={page.slice(3, 6)} />
<Row3 articles={page.slice(6, 9)} />
<Switch>
<Match when={articles.length === 1}>
<Row1 article={articles[0]} noauthor={true} nodate={true} />
</Match>
<Match when={articles.length === 2}>
<Row2 articles={articles} noauthor={true} nodate={true} isEqual={true} />
</Match>
<Match when={articles.length === 3}>
<Row3 articles={articles} noauthor={true} nodate={true} />
</Match>
</Switch>
</>
)}
</For>
);
}}
</For>
</LoadMoreWrapper>
</Suspense>
</div>

View File

@ -138,9 +138,8 @@ export default function AuthorPage(props: RouteSectionProps<AuthorPageProps>) {
>
<AuthorView
author={author() as Author}
selectedTab={props.params.tab}
authorSlug={props.params.slug}
shouts={authorShouts()}
shouts={authorShouts() || []}
/>
</LoadMoreWrapper>
</ReactionsProvider>

View File

@ -62,34 +62,38 @@ export default function TopicPage(props: RouteSectionProps<TopicPageProps>) {
const [desc, setDesc] = createSignal<string>('')
const [cover, setCover] = createSignal<string>('')
const [viewed, setViewed] = createSignal(false)
createEffect(on([topics, () => window], ([ttt, win]) => {
if (ttt && win) {
// console.debug('all topics:', ttt)
ttt && addTopics(ttt)
const tpc = ttt.find((x) => x.slug === props.params.slug)
if (!tpc) return
setTopic(tpc)
setTitle(() => `${t('Discours')}${topic()?.title ? ` :: ${topic()?.title}` : ''}`)
setDesc(() =>
topic()?.body
? descFromBody(topic()?.body || '')
: t('The most interesting publications on the topic', { topicName: title() })
)
setCover(() =>
topic()?.pic ? getImageUrl(topic()?.pic || '', { width: 1200 }) : '/logo.png'
)
createEffect(
on(
[topics, () => window],
([ttt, win]) => {
if (ttt && win) {
// console.debug('all topics:', ttt)
ttt && addTopics(ttt)
const tpc = ttt.find((x) => x.slug === props.params.slug)
if (!tpc) return
setTopic(tpc)
setTitle(() => `${t('Discours')}${topic()?.title ? ` :: ${topic()?.title}` : ''}`)
setDesc(() =>
topic()?.body
? descFromBody(topic()?.body || '')
: t('The most interesting publications on the topic', { topicName: title() })
)
setCover(() => (topic()?.pic ? getImageUrl(topic()?.pic || '', { width: 1200 }) : '/logo.png'))
// views google counter increment
if (viewed()) {
window?.gtag?.('event', 'page_view', {
page_title: tpc.title,
page_location: window?.location.href,
page_path: window?.location.pathname
})
setViewed(true)
}
}
}, {}))
// views google counter increment
if (!viewed()) {
window?.gtag?.('event', 'page_view', {
page_title: tpc.title,
page_location: window?.location.href,
page_path: window?.location.pathname
})
setViewed(true)
}
}
},
{}
)
)
return (
<Show