import { A, useLocation, useParams } from '@solidjs/router' import { clsx } from 'clsx' import { For, Match, Show, Switch, createEffect, createMemo, createSignal, on, onMount } from 'solid-js' import { Loading } from '~/components/_shared/Loading' import { useAuthors } from '~/context/authors' import { useFeed } from '~/context/feed' import { useFollowing } from '~/context/following' import { useGraphQL } from '~/context/graphql' import { useLocalize } from '~/context/localize' import { useSession } from '~/context/session' import { loadReactions } from '~/graphql/api/public' import loadShoutsQuery from '~/graphql/query/core/articles-load-by' 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/sortby' import { restoreScrollPosition, saveScrollPosition } from '~/utils/scroll' import { splitToPages } from '~/utils/splitToPages' import stylesArticle from '../../Article/Article.module.scss' import { Comment } from '../../Article/Comment' import { AuthorCard } from '../../Author/AuthorCard' import { AuthorShoutsRating } from '../../Author/AuthorShoutsRating' import { Placeholder } from '../../Feed/Placeholder' import { Row1 } from '../../Feed/Row1' import { Row2 } from '../../Feed/Row2' import { Row3 } from '../../Feed/Row3' import styles from './Author.module.scss' type Props = { authorSlug: string shouts?: Shout[] author?: Author topics?: Topic[] selectedTab: string } export const PRERENDERED_ARTICLES_COUNT = 12 const LOAD_MORE_PAGE_SIZE = 9 export const AuthorView = (props: Props) => { console.debug('[components.AuthorView] reactive context init...') const { t } = useLocalize() const params = useParams() const { followers: myFollowers, follows: myFollows } = useFollowing() const { session } = useSession() const me = createMemo(() => session()?.user?.app_data?.profile as Author) const [authorSlug, setSlug] = createSignal(props.authorSlug) const { sortedFeed } = useFeed() const loc = useLocation() const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false) const [isBioExpanded, setIsBioExpanded] = createSignal(false) const { loadAuthor, authorsEntities } = useAuthors() const [author, setAuthor] = createSignal() const [followers, setFollowers] = createSignal([] as Author[]) const [following, changeFollowing] = createSignal>([] as Array) // flat AuthorFollowsResult const [showExpandBioControl, setShowExpandBioControl] = createSignal(false) const [commented, setCommented] = createSignal([]) const { query } = useGraphQL() // пагинация загрузки ленты постов const loadMore = async () => { saveScrollPosition() const resp = await query(loadShoutsQuery, { filters: { author: props.authorSlug }, limit: LOAD_MORE_PAGE_SIZE, offset: sortedFeed().length }) const hasMore = resp?.data?.load_shouts_by?.hasMore setIsLoadMoreButtonVisible(hasMore) restoreScrollPosition() } // 1 // проверяет не собственный ли это профиль, иначе - загружает const [isFetching, setIsFetching] = createSignal(false) createEffect( on([() => session()?.user?.app_data?.profile, () => props.authorSlug || ''], async ([me, slug]) => { const my = slug && me?.slug === slug if (my) { console.debug('[Author] my profile precached') if (me) { setAuthor(me) if (myFollowers()) setFollowers((myFollowers() || []) as Author[]) changeFollowing([...(myFollows?.topics || []), ...(myFollows?.authors || [])]) } } else if (slug && !isFetching()) { setIsFetching(true) setSlug(slug) await loadAuthor({ slug }) setIsFetching(false) // Сброс состояния загрузки после завершения } }) ) // 2 // догружает подписки автора createEffect( on( [followers, () => props.author || authorsEntities()[authorSlug()]], async ([current, found]) => { if (current) return if (!found) return setAuthor(found) console.info(`[Author] profile for @${authorSlug()} fetched`) const followsResp = await query(getAuthorFollowsQuery, { slug: authorSlug() }).toPromise() const follows = followsResp?.data?.get_author_followers || {} changeFollowing([...(follows?.authors || []), ...(follows?.topics || [])]) console.info(`[Author] follows for @${authorSlug()} fetched`) const followersResp = await query(getAuthorFollowersQuery, { slug: authorSlug() }).toPromise() setFollowers(followersResp?.data?.get_author_followers || []) console.info(`[Author] followers for @${authorSlug()} fetched`) setIsFetching(false) }, { defer: true } ) ) // 3 // догружает ленту и комментарии createEffect( on( () => author() as Author, async (profile: Author) => { if (!commented() && profile) { await loadMore() const commentsFetcher = loadReactions({ by: { comment: true, created_by: profile.id } }) const ccc = await commentsFetcher() if (ccc) setCommented((_) => ccc || []) } } // { defer: true }, ) ) let bioContainerRef: HTMLDivElement let bioWrapperRef: HTMLDivElement const checkBioHeight = () => { if (bioContainerRef) { setShowExpandBioControl(bioContainerRef.offsetHeight > bioWrapperRef.offsetHeight) } } const pages = createMemo(() => splitToPages(sortedFeed(), PRERENDERED_ARTICLES_COUNT, LOAD_MORE_PAGE_SIZE) ) const handleDeleteComment = (id: number) => { setCommented((prev) => (prev || []).filter((comment) => comment.id !== id)) } onMount(checkBioHeight) return (
}> <>
{t('All posts rating')}
(bioWrapperRef = el)} class={styles.longBio} classList={{ [styles.longBioExpanded]: isBioExpanded() }} >
(bioContainerRef = el)} innerHTML={author()?.about || ''} />
    {(comment) => ( handleDeleteComment(id)} /> )}
0}> 1}> 3}> {(page) => ( <> )}

) }