tab-navigation-fix
This commit is contained in:
parent
7ca7acc487
commit
22f44ee0ec
|
@ -1,6 +1,6 @@
|
|||
import { A, useLocation } from '@solidjs/router'
|
||||
import { A, useLocation, useParams } from '@solidjs/router'
|
||||
import { clsx } from 'clsx'
|
||||
import { For, Match, Show, Switch, createEffect, createMemo, createSignal } from 'solid-js'
|
||||
import { For, Match, Show, Switch, createEffect, createMemo, createSignal, on } from 'solid-js'
|
||||
import { Loading } from '~/components/_shared/Loading'
|
||||
import { coreApiUrl } from '~/config'
|
||||
import { useAuthors } from '~/context/authors'
|
||||
|
@ -37,6 +37,8 @@ export const AuthorView = (props: AuthorViewProps) => {
|
|||
// contexts
|
||||
const { t } = useLocalize()
|
||||
const loc = useLocation()
|
||||
const params = useParams()
|
||||
const [currentTab, setCurrentTab] = createSignal<string>(props.selectedTab)
|
||||
|
||||
const { session } = useSession()
|
||||
const client = createMemo(() => graphqlClientCreate(coreApiUrl, session()?.access_token))
|
||||
|
@ -58,6 +60,18 @@ export const AuthorView = (props: AuthorViewProps) => {
|
|||
paginate((props.shouts || []).slice(1), PRERENDERED_ARTICLES_COUNT, LOAD_MORE_PAGE_SIZE)
|
||||
)
|
||||
|
||||
// Переход по табам
|
||||
createEffect(
|
||||
on(
|
||||
() => params.tab,
|
||||
(tab: string) => {
|
||||
// Обновляем текущую вкладку
|
||||
setCurrentTab(tab || '')
|
||||
},
|
||||
{}
|
||||
)
|
||||
)
|
||||
|
||||
// Объединенный эффект для загрузки автора и его подписок
|
||||
createEffect(async () => {
|
||||
const meData = session()?.user?.app_data?.profile as Author
|
||||
|
@ -105,6 +119,30 @@ export const AuthorView = (props: AuthorViewProps) => {
|
|||
setCommented((prev) => prev.filter((comment) => comment.id !== id))
|
||||
}
|
||||
|
||||
const TabNavigator = () => (
|
||||
<div class="col-md-16">
|
||||
<ul class="view-switcher">
|
||||
<li classList={{ 'view-switcher__item--selected': !currentTab() }}>
|
||||
<A href={`/@${props.authorSlug}`}>{t('Publications')}</A>
|
||||
<Show when={author()?.stat}>
|
||||
<span class="view-switcher__counter">{author()?.stat?.shouts || 0}</span>
|
||||
</Show>
|
||||
</li>
|
||||
<li classList={{ 'view-switcher__item--selected': currentTab() === 'comments' }}>
|
||||
<A href={`/@${props.authorSlug}/comments`}>{t('Comments')}</A>
|
||||
<Show when={author()?.stat}>
|
||||
<span class="view-switcher__counter">{author()?.stat?.comments || 0}</span>
|
||||
</Show>
|
||||
</li>
|
||||
<li classList={{ 'view-switcher__item--selected': currentTab() === 'about' }}>
|
||||
<A onClick={() => checkBioHeight()} href={`/@${props.authorSlug}/about`}>
|
||||
{t('About the author')}
|
||||
</A>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
|
||||
return (
|
||||
<div class={styles.authorPage}>
|
||||
<div class="wide-container">
|
||||
|
@ -118,27 +156,7 @@ export const AuthorView = (props: AuthorViewProps) => {
|
|||
/>
|
||||
</div>
|
||||
<div class={clsx(styles.groupControls, 'row')}>
|
||||
<div class="col-md-16">
|
||||
<ul class="view-switcher">
|
||||
<li classList={{ 'view-switcher__item--selected': !props.selectedTab }}>
|
||||
<A href={`/@${props.authorSlug}`}>{t('Publications')}</A>
|
||||
<Show when={author()?.stat}>
|
||||
<span class="view-switcher__counter">{author()?.stat?.shouts || 0}</span>
|
||||
</Show>
|
||||
</li>
|
||||
<li classList={{ 'view-switcher__item--selected': props.selectedTab === 'comment' }}>
|
||||
<A href={`/@${props.authorSlug}/comments`}>{t('Comments')}</A>
|
||||
<Show when={author()?.stat}>
|
||||
<span class="view-switcher__counter">{author()?.stat?.comments || 0}</span>
|
||||
</Show>
|
||||
</li>
|
||||
<li classList={{ 'view-switcher__item--selected': props.selectedTab === 'about' }}>
|
||||
<A onClick={() => checkBioHeight()} href={`/@${props.authorSlug}/about`}>
|
||||
{t('About the author')}
|
||||
</A>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<TabNavigator />
|
||||
<div class={clsx('col-md-8', styles.additionalControls)}>
|
||||
<Show when={author()?.stat?.rating || author()?.stat?.rating === 0}>
|
||||
<div class={styles.ratingContainer}>
|
||||
|
@ -153,7 +171,8 @@ export const AuthorView = (props: AuthorViewProps) => {
|
|||
</div>
|
||||
|
||||
<Switch>
|
||||
<Match when={props.selectedTab === 'about'}>
|
||||
|
||||
<Match when={currentTab() === 'about'}>
|
||||
<div class="wide-container">
|
||||
<div class="row">
|
||||
<div class="col-md-20 col-lg-18">
|
||||
|
@ -177,7 +196,9 @@ export const AuthorView = (props: AuthorViewProps) => {
|
|||
</div>
|
||||
</div>
|
||||
</Match>
|
||||
<Match when={props.selectedTab === 'comments'}>
|
||||
|
||||
<Match when={currentTab() === 'comments'}>
|
||||
|
||||
<Show when={me()?.slug === props.authorSlug && !me().stat?.comments}>
|
||||
<div class="wide-container">
|
||||
<Placeholder type={loc?.pathname} mode="profile" />
|
||||
|
@ -203,7 +224,8 @@ export const AuthorView = (props: AuthorViewProps) => {
|
|||
</div>
|
||||
</div>
|
||||
</Match>
|
||||
<Match when={!props.selectedTab}>
|
||||
|
||||
<Match when={!currentTab()}>
|
||||
<Show when={me()?.slug === props.authorSlug && !me().stat?.shouts}>
|
||||
<div class="wide-container">
|
||||
<Placeholder type={loc?.pathname} mode="profile" />
|
||||
|
@ -239,6 +261,7 @@ export const AuthorView = (props: AuthorViewProps) => {
|
|||
</Show>
|
||||
</Show>
|
||||
</Match>
|
||||
|
||||
</Switch>
|
||||
</div>
|
||||
)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { RouteSectionProps } from '@solidjs/router'
|
||||
import { ErrorBoundary, Suspense, createEffect, createMemo, createSignal, on } from 'solid-js'
|
||||
import { RouteSectionProps, createAsync } from '@solidjs/router'
|
||||
import { ErrorBoundary, Suspense, createEffect, createSignal, on } from 'solid-js'
|
||||
import { AuthorView } from '~/components/Views/Author'
|
||||
import { FourOuFourView } from '~/components/Views/FourOuFour'
|
||||
import { LoadMoreItems, LoadMoreWrapper } from '~/components/_shared/LoadMoreWrapper'
|
||||
|
@ -39,9 +39,10 @@ const fetchAuthor = async (slug: string) => {
|
|||
export const route = {
|
||||
load: async ({ params, location: { query } }: RouteSectionProps<{ articles: Shout[] }>) => {
|
||||
const offset: number = Number.parseInt(query.offset, 10)
|
||||
console.debug('route loading with offset', offset)
|
||||
return {
|
||||
author: await fetchAuthor(params.slug),
|
||||
shouts: await fetchAuthorShouts(params.slug, offset),
|
||||
articles: await fetchAuthorShouts(params.slug, offset),
|
||||
topics: await fetchAllTopics()
|
||||
}
|
||||
}
|
||||
|
@ -50,39 +51,17 @@ export const route = {
|
|||
export type AuthorPageProps = { articles?: Shout[]; author?: Author; topics?: Topic[] }
|
||||
|
||||
export default function AuthorPage(props: RouteSectionProps<AuthorPageProps>) {
|
||||
const { t } = useLocalize()
|
||||
|
||||
// load author's profile
|
||||
const { addAuthor, authorsEntities } = useAuthors()
|
||||
const [author, setAuthor] = createSignal<Author | undefined>(undefined)
|
||||
|
||||
const { t } = useLocalize()
|
||||
const title = createMemo(() => `${author()?.name || ''}`)
|
||||
|
||||
createEffect(() => {
|
||||
if (author()) {
|
||||
console.debug('[routes] author/[slug] author loaded fx')
|
||||
window?.gtag?.('event', 'page_view', {
|
||||
page_title: author()?.name || '',
|
||||
page_location: window?.location.href || '',
|
||||
page_path: window?.location.pathname || ''
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const cover = createMemo(() =>
|
||||
author()?.pic
|
||||
? getImageUrl(author()?.pic || '', { width: 1200 })
|
||||
: getImageUrl('production/image/logo_image.png')
|
||||
)
|
||||
|
||||
// author shouts
|
||||
const { addFeed, feedByAuthor } = useFeed()
|
||||
const shoutsByAuthor = createMemo(() => feedByAuthor()[props.params.slug])
|
||||
|
||||
createEffect(
|
||||
on(
|
||||
[() => props.params.slug || '', author],
|
||||
async ([slug, profile]) => {
|
||||
on(author,
|
||||
async (profile) => {
|
||||
// update only if no profile loaded
|
||||
if (!profile) {
|
||||
const loadedAuthor = authorsEntities()[slug] || (await fetchAuthor(slug))
|
||||
const loadedAuthor = authorsEntities()[props.params.slug] || (await fetchAuthor(props.params.slug))
|
||||
if (loadedAuthor) {
|
||||
addAuthor(loadedAuthor)
|
||||
setAuthor(loadedAuthor)
|
||||
|
@ -93,6 +72,48 @@ export default function AuthorPage(props: RouteSectionProps<AuthorPageProps>) {
|
|||
)
|
||||
)
|
||||
|
||||
// author's data, view counter
|
||||
const [title, setTitle] = createSignal<string>('')
|
||||
const [desc, setDesc] = createSignal<string>('')
|
||||
const [cover, setCover] = createSignal<string>('')
|
||||
const [viewed, setViewed] = createSignal(false)
|
||||
createEffect(
|
||||
on(
|
||||
[author, () => window],
|
||||
([a, win]) => {
|
||||
if (a && win) {
|
||||
console.debug('[routes] author/[slug] author loaded fx')
|
||||
if (!a) return
|
||||
setTitle(() => `${t('Discours')}${a.name ? ` :: ${a.name}` : ''}`)
|
||||
setDesc(() => a.about || a.bio || '')
|
||||
setCover(() => (a.pic ? getImageUrl(a.pic || '', { width: 1200 }) : 'log.png'))
|
||||
|
||||
// views google counter increment
|
||||
if (!viewed()) {
|
||||
window?.gtag?.('event', 'page_view', {
|
||||
page_title: author()?.name || '',
|
||||
page_location: window?.location.href || '',
|
||||
page_path: window?.location.pathname || ''
|
||||
})
|
||||
setViewed(true)
|
||||
}
|
||||
}
|
||||
},
|
||||
{}
|
||||
)
|
||||
)
|
||||
|
||||
// author's shouts
|
||||
const { addFeed, feedByAuthor } = useFeed()
|
||||
const [loadMoreHidden, setLoadMoreHidden] = createSignal(true)
|
||||
const authorShouts = createAsync(async () => {
|
||||
const sss: Shout[] = props.data.articles as Shout[] || feedByAuthor()[props.params.slug] || []
|
||||
const result = sss || (await fetchAuthorShouts(props.params.slug, 0))
|
||||
if (!result) setLoadMoreHidden(true)
|
||||
return result
|
||||
})
|
||||
|
||||
// load more shouts
|
||||
const loadAuthorShoutsMore = async (offset: number) => {
|
||||
const loadedShouts = await fetchAuthorShouts(props.params.slug, offset)
|
||||
loadedShouts && addFeed(loadedShouts)
|
||||
|
@ -103,19 +124,23 @@ export default function AuthorPage(props: RouteSectionProps<AuthorPageProps>) {
|
|||
<ErrorBoundary fallback={(_err) => <FourOuFourView />}>
|
||||
<Suspense fallback={<Loading />}>
|
||||
<PageLayout
|
||||
title={`${t('Discours')} :: ${title()}`}
|
||||
title={title()}
|
||||
headerTitle={author()?.name || ''}
|
||||
slug={author()?.slug}
|
||||
desc={author()?.about || author()?.bio || ''}
|
||||
desc={desc()}
|
||||
cover={cover()}
|
||||
>
|
||||
<ReactionsProvider>
|
||||
<LoadMoreWrapper loadFunction={loadAuthorShoutsMore} pageSize={SHOUTS_PER_PAGE}>
|
||||
<LoadMoreWrapper
|
||||
loadFunction={loadAuthorShoutsMore}
|
||||
pageSize={SHOUTS_PER_PAGE}
|
||||
hidden={loadMoreHidden()}
|
||||
>
|
||||
<AuthorView
|
||||
author={author() as Author}
|
||||
selectedTab={props.params.tab}
|
||||
authorSlug={props.params.slug}
|
||||
shouts={shoutsByAuthor()}
|
||||
shouts={authorShouts()}
|
||||
/>
|
||||
</LoadMoreWrapper>
|
||||
</ReactionsProvider>
|
||||
|
|
Loading…
Reference in New Issue
Block a user