import { useSearchParams } from '@solidjs/router' import { clsx } from 'clsx' import { For, Show, Suspense, createEffect, createMemo, createSignal, on, onMount } from 'solid-js' import { useAuthors } from '~/context/authors' import { useFeed } from '~/context/feed' import { useLocalize } from '~/context/localize' import { useTopics } from '~/context/topics' import { loadAuthors, loadFollowersByTopic, loadShouts } from '~/graphql/api/public' 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' import { Row1 } from '../Feed/Row1' import { Row2 } from '../Feed/Row2' import { Row3 } from '../Feed/Row3' import { FullTopic } from '../Topic/Full' 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 { topic: Topic shouts: Shout[] topicSlug: string followers?: Author[] selectedTab?: TopicFeedSortBy } export const PRERENDERED_ARTICLES_COUNT = 28 const LOAD_MORE_PAGE_SIZE = 9 // Row3 + Row3 + Row3 export const TopicView = (props: Props) => { const { t } = useLocalize() const { feedByTopic, addFeed } = useFeed() const { topicEntities } = useTopics() const { authorsByTopic } = useAuthors() const [searchParams, changeSearchParams] = useSearchParams<{ by: TopicFeedSortBy }>() const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false) const [favoriteTopArticles, setFavoriteTopArticles] = createSignal([]) const [reactedTopMonthArticles, setReactedTopMonthArticles] = createSignal([]) const [topic, setTopic] = createSignal() const [followers, setFollowers] = createSignal(props.followers || []) const sortedFeed = createMemo(() => feedByTopic()[topic()?.slug || ''] || []) // TODO: filter + sort const loadTopicFollowers = async () => { const topicFollowersFetcher = loadFollowersByTopic(props.topicSlug) const topicFollowers = await topicFollowersFetcher() topicFollowers && setFollowers(topicFollowers) } const [topicAuthors, setTopicAuthors] = createSignal([]) const loadTopicAuthors = async () => { const by: AuthorsBy = { topic: props.topicSlug } const topicAuthorsFetcher = await loadAuthors({ by, limit: 10, offset: 0 }) const result = await topicAuthorsFetcher() result && setTopicAuthors(result) } const loadFavoriteTopArticles = async () => { const options: LoadShoutsOptions = { filters: { featured: true, topic: props.topicSlug }, limit: 10, random_limit: 100 } const topicRandomShoutsFetcher = loadShouts(options) const result = await topicRandomShoutsFetcher() result && setFavoriteTopArticles(result) } const loadReactedTopMonthArticles = async () => { const now = new Date() const after = getUnixtime(new Date(now.setMonth(now.getMonth() - 1))) const options: LoadShoutsOptions = { filters: { after: after, featured: true, topic: props.topicSlug }, limit: 10, random_limit: 10 } const reactedTopMonthShoutsFetcher = loadShouts(options) const result = await reactedTopMonthShoutsFetcher() result && setReactedTopMonthArticles(result) } // второй этап начальной загрузки данных createEffect( on( topicEntities, (ttt: Record) => { if (props.topicSlug in ttt) { Promise.all([ loadFavoriteTopArticles(), loadReactedTopMonthArticles(), loadTopicAuthors(), loadTopicFollowers() ]).finally(() => { setTopic(ttt[props.topicSlug]) }) } }, { defer: true } ) ) // дозагрузка const loadMore = async () => { saveScrollPosition() const amountBefore = feedByTopic()?.[props.topicSlug]?.length || 0 const topicShoutsFetcher = loadShouts({ filters: { topic: props.topicSlug }, limit: SHOUTS_PER_PAGE, offset: amountBefore }) const result = await topicShoutsFetcher() if (result) { addFeed(result) const amountAfter = feedByTopic()[props.topicSlug].length setIsLoadMoreButtonVisible(amountBefore !== amountAfter) } restoreScrollPosition() } onMount(() => { if (sortedFeed() || [].length === PRERENDERED_ARTICLES_COUNT) { loadMore() } }) /* const selectionTitle = createMemo(() => { const m = searchParams?.by if (m === 'viewed') return t('Top viewed') if (m === 'rating') return t('Top rated') if (m === 'commented') return t('Top discussed') return t('Top recent') }) */ const pages = createMemo(() => paginate(sortedFeed(), PRERENDERED_ARTICLES_COUNT, LOAD_MORE_PAGE_SIZE) ) return (
}>
  • {/*TODO: server sort*/} {/*
  • */} {/* */} {/*
  • */} {/*
  • */} {/* */} {/*
  • */} {/*
  • */} {/* */} {/*
  • */}
{`${t('Show')} `} {t('All posts')}
0} keyed={true}> 0} keyed={true}> 14}> {(page) => ( <> )}

) }