import { Meta, Title } from '@solidjs/meta' import { A, useLocation, useMatch } from '@solidjs/router' import { clsx } from 'clsx' import { For, Match, Show, Switch, createEffect, createMemo, createSignal, on, onMount } from 'solid-js' import { useAuthors } from '~/context/authors' import { useGraphQL } from '~/context/graphql' import { useUI } from '~/context/ui' import { useFeed } from '../../../context/feed' import { useFollowing } from '../../../context/following' import { useLocalize } from '../../../context/localize' import { useSession } from '../../../context/session' 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 loadReactionsBy from '../../../graphql/query/core/reactions-load-by' import type { Author, Reaction, Shout, Topic } from '../../../graphql/schema/core.gen' import { getImageUrl } from '../../../utils/getImageUrl' import { getDescription } from '../../../utils/meta' import { restoreScrollPosition, saveScrollPosition } from '../../../utils/scroll' import { byCreated } from '../../../utils/sortby' 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 { Loading } from '../../_shared/Loading' import styles from './Author.module.scss' type Props = { authorSlug: string shouts?: Shout[] author?: Author } export const PRERENDERED_ARTICLES_COUNT = 12 const LOAD_MORE_PAGE_SIZE = 9 export const AuthorView = (props: Props) => { const { t } = useLocalize() const { followers: myFollowers, follows: myFollows } = useFollowing() const { session } = useSession() const me = createMemo(() => session()?.user?.app_data?.profile as Author) const [slug, setSlug] = createSignal(props.authorSlug) const { sortedFeed } = useFeed() const { modal, hideModal } = useUI() const loc = useLocation() const matchAuthor = useMatch(() => '/author') const matchComments = useMatch(() => '/author/:authorId/comments') const matchAbout = useMatch(() => '/author/:authorId/about') 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, s]) => { const my = s && me?.slug === s 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 (s && !isFetching()) { setIsFetching(true) setSlug(s) await loadAuthor(s) setIsFetching(false) // Сброс состояния загрузки после завершения } }) ) // 3 // after fetch loading following data createEffect( on( [followers, () => authorsEntities()[slug()]], async ([current, found]) => { if (current) return if (!found) return setAuthor(found) console.info(`[Author] profile for @${slug()} fetched`) const followsResp = await query(getAuthorFollowsQuery, { slug: slug() }).toPromise() const follows = followsResp?.data?.get_author_followers || {} changeFollowing([...(follows?.authors || []), ...(follows?.topics || [])]) console.info(`[Author] follows for @${slug()} fetched`) const followersResp = await query(getAuthorFollowersQuery, { slug: slug() }).toPromise() setFollowers(followersResp?.data?.get_author_followers || []) console.info(`[Author] followers for @${slug()} fetched`) setIsFetching(false) }, { defer: true } ) ) // догружает ленту и комментарии createEffect( on( () => author() as Author, async (profile: Author) => { if (!commented() && profile) { await loadMore() const resp = await query(loadReactionsBy, { by: { comment: true, created_by: profile.id } }).toPromise() const ccc = resp?.data?.load_reactions_by if (ccc) setCommented(ccc) } } // { defer: true }, ) ) let bioContainerRef: HTMLDivElement let bioWrapperRef: HTMLDivElement const checkBioHeight = () => { if (bioContainerRef) { setShowExpandBioControl(bioContainerRef.offsetHeight > bioWrapperRef.offsetHeight) } } onMount(() => { if (!modal()) hideModal() checkBioHeight() }) const pages = createMemo(() => splitToPages(sortedFeed(), PRERENDERED_ARTICLES_COUNT, LOAD_MORE_PAGE_SIZE) ) const ogImage = createMemo(() => author()?.pic ? getImageUrl(author()?.pic || '', { width: 1200 }) : getImageUrl('production/image/logo_image.png') ) const description = createMemo(() => getDescription(author()?.bio || '')) const handleDeleteComment = (id: number) => { setCommented((prev) => (prev || []).filter((comment) => comment.id !== id)) } return (
{author()?.name}
}> <>
{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) => ( <> )}

) }