One page with subscriptions to authors and topics (#99)
* One page with subscriptions to authors and topics * resolve conversation
This commit is contained in:
parent
c60b7e5c53
commit
afcebb10b1
|
@ -14,7 +14,6 @@
|
||||||
"Artworks": "Artworks",
|
"Artworks": "Artworks",
|
||||||
"Audio": "Audio",
|
"Audio": "Audio",
|
||||||
"Author": "Author",
|
"Author": "Author",
|
||||||
"Author subscriptions": "Подписки на авторов",
|
|
||||||
"Authors": "Authors",
|
"Authors": "Authors",
|
||||||
"Back to main page": "Back to main page",
|
"Back to main page": "Back to main page",
|
||||||
"Become an author": "Become an author",
|
"Become an author": "Become an author",
|
||||||
|
@ -220,7 +219,6 @@
|
||||||
"Top topics": "Interesting topics",
|
"Top topics": "Interesting topics",
|
||||||
"Top viewed": "Most viewed",
|
"Top viewed": "Most viewed",
|
||||||
"Topic is supported by": "Topic is supported by",
|
"Topic is supported by": "Topic is supported by",
|
||||||
"Topic subscriptions": "Подписки на темы",
|
|
||||||
"Topics": "Topics",
|
"Topics": "Topics",
|
||||||
"Topics which supported by author": "Topics which supported by author",
|
"Topics which supported by author": "Topics which supported by author",
|
||||||
"Try to find another way": "Try to find another way",
|
"Try to find another way": "Try to find another way",
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
"Artworks": "Артворки",
|
"Artworks": "Артворки",
|
||||||
"Audio": "Аудио",
|
"Audio": "Аудио",
|
||||||
"Author": "Автор",
|
"Author": "Автор",
|
||||||
"Author subscriptions": "Подписки на авторов",
|
|
||||||
"Authors": "Авторы",
|
"Authors": "Авторы",
|
||||||
"Back to main page": "Вернуться на главную",
|
"Back to main page": "Вернуться на главную",
|
||||||
"Become an author": "Стать автором",
|
"Become an author": "Стать автором",
|
||||||
|
@ -233,7 +232,6 @@
|
||||||
"Top topics": "Интересные темы",
|
"Top topics": "Интересные темы",
|
||||||
"Top viewed": "Самое читаемое",
|
"Top viewed": "Самое читаемое",
|
||||||
"Topic is supported by": "Тему поддерживают",
|
"Topic is supported by": "Тему поддерживают",
|
||||||
"Topic subscriptions": "Подписки на темы",
|
|
||||||
"Topics": "Темы",
|
"Topics": "Темы",
|
||||||
"Topics which supported by author": "Автор поддерживает темы",
|
"Topics which supported by author": "Автор поддерживает темы",
|
||||||
"Try to find another way": "Попробуйте найти по-другому",
|
"Try to find another way": "Попробуйте найти по-другому",
|
||||||
|
|
|
@ -71,3 +71,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.loadingWrapper {
|
||||||
|
position: relative;
|
||||||
|
min-height: 40vh;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
|
@ -1,25 +1,26 @@
|
||||||
import { Show, createMemo, createSignal, Switch, onMount, For, Match, createEffect } from 'solid-js'
|
import { Show, createMemo, createSignal, Switch, onMount, For, Match, createEffect } from 'solid-js'
|
||||||
import type { Author, Shout, Topic } from '../../graphql/types.gen'
|
import type { Author, Shout, Topic } from '../../../graphql/types.gen'
|
||||||
import { Row1 } from '../Feed/Row1'
|
import { Row1 } from '../../Feed/Row1'
|
||||||
import { Row2 } from '../Feed/Row2'
|
import { Row2 } from '../../Feed/Row2'
|
||||||
import { AuthorFull } from '../Author/Full'
|
import { AuthorFull } from '../../Author/Full'
|
||||||
|
|
||||||
import { useAuthorsStore } from '../../stores/zine/authors'
|
import { useAuthorsStore } from '../../../stores/zine/authors'
|
||||||
import { loadShouts, useArticlesStore } from '../../stores/zine/articles'
|
import { loadShouts, useArticlesStore } from '../../../stores/zine/articles'
|
||||||
import { useRouter } from '../../stores/router'
|
import { useRouter } from '../../../stores/router'
|
||||||
import { restoreScrollPosition, saveScrollPosition } from '../../utils/scroll'
|
import { restoreScrollPosition, saveScrollPosition } from '../../../utils/scroll'
|
||||||
import { splitToPages } from '../../utils/splitToPages'
|
import { splitToPages } from '../../../utils/splitToPages'
|
||||||
import styles from './Author.module.scss'
|
import styles from './Author.module.scss'
|
||||||
import stylesArticle from '../Article/Article.module.scss'
|
import stylesArticle from '../../Article/Article.module.scss'
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
import Userpic from '../Author/Userpic'
|
import Userpic from '../../Author/Userpic'
|
||||||
import { Popup } from '../_shared/Popup'
|
import { Popup } from '../../_shared/Popup'
|
||||||
import { AuthorCard } from '../Author/AuthorCard'
|
import { AuthorCard } from '../../Author/AuthorCard'
|
||||||
import { apiClient } from '../../utils/apiClient'
|
import { apiClient } from '../../../utils/apiClient'
|
||||||
import { Comment } from '../Article/Comment'
|
import { Comment } from '../../Article/Comment'
|
||||||
import { useLocalize } from '../../context/localize'
|
import { useLocalize } from '../../../context/localize'
|
||||||
import { AuthorRatingControl } from '../Author/AuthorRatingControl'
|
import { AuthorRatingControl } from '../../Author/AuthorRatingControl'
|
||||||
import { TopicCard } from '../Topic/Card'
|
import { TopicCard } from '../../Topic/Card'
|
||||||
|
import { Loading } from '../../_shared/Loading'
|
||||||
|
|
||||||
type AuthorProps = {
|
type AuthorProps = {
|
||||||
shouts: Shout[]
|
shouts: Shout[]
|
||||||
|
@ -34,8 +35,7 @@ export type AuthorPageSearchParams = {
|
||||||
| 'rating'
|
| 'rating'
|
||||||
| 'commented'
|
| 'commented'
|
||||||
| 'recent'
|
| 'recent'
|
||||||
| 'subscribed-authors'
|
| 'subscriptions'
|
||||||
| 'subscribed-topics'
|
|
||||||
| 'followers'
|
| 'followers'
|
||||||
| 'about'
|
| 'about'
|
||||||
| 'popular'
|
| 'popular'
|
||||||
|
@ -44,6 +44,9 @@ export type AuthorPageSearchParams = {
|
||||||
export const PRERENDERED_ARTICLES_COUNT = 12
|
export const PRERENDERED_ARTICLES_COUNT = 12
|
||||||
const LOAD_MORE_PAGE_SIZE = 9
|
const LOAD_MORE_PAGE_SIZE = 9
|
||||||
|
|
||||||
|
function isAuthor(value: Author | Topic): value is Author {
|
||||||
|
return 'name' in value
|
||||||
|
}
|
||||||
export const AuthorView = (props: AuthorProps) => {
|
export const AuthorView = (props: AuthorProps) => {
|
||||||
const { t } = useLocalize()
|
const { t } = useLocalize()
|
||||||
const { sortedArticles } = useArticlesStore({ shouts: props.shouts })
|
const { sortedArticles } = useArticlesStore({ shouts: props.shouts })
|
||||||
|
@ -52,8 +55,23 @@ export const AuthorView = (props: AuthorProps) => {
|
||||||
const author = authorEntities()[props.authorSlug]
|
const author = authorEntities()[props.authorSlug]
|
||||||
const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false)
|
const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false)
|
||||||
const [followers, setFollowers] = createSignal<Author[]>([])
|
const [followers, setFollowers] = createSignal<Author[]>([])
|
||||||
const [followingUsers, setFollowingUsers] = createSignal<Author[]>([])
|
const [subscriptions, setSubscriptions] = createSignal<Array<Author | Topic>>([])
|
||||||
const [subscribedTopics, setSubscribedTopics] = createSignal<Topic[]>([])
|
const [isLoaded, setIsLoaded] = createSignal<boolean>()
|
||||||
|
|
||||||
|
const fetchSubscriptions = async (): Promise<{ authors: Author[]; topics: Topic[] }> => {
|
||||||
|
try {
|
||||||
|
const [getAuthors, getTopics] = await Promise.all([
|
||||||
|
apiClient.getAuthorFollowingUsers({ slug: props.authorSlug }),
|
||||||
|
apiClient.getAuthorFollowingTopics({ slug: props.authorSlug })
|
||||||
|
])
|
||||||
|
const authors = getAuthors
|
||||||
|
const topics = getTopics
|
||||||
|
return { authors, topics }
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[fetchSubscriptions] :', error)
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
try {
|
try {
|
||||||
|
@ -62,25 +80,9 @@ export const AuthorView = (props: AuthorProps) => {
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('[getAuthorFollowers]', error)
|
console.log('[getAuthorFollowers]', error)
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
|
||||||
const authorSubscriptionsUsers = await apiClient.getAuthorFollowingUsers({ slug: props.authorSlug })
|
|
||||||
setFollowingUsers(authorSubscriptionsUsers)
|
|
||||||
} catch (error) {
|
|
||||||
console.log('[getAuthorFollowingUsers]', error)
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const authorSubscriptionsTopics = await apiClient.getAuthorFollowingTopics({ slug: props.authorSlug })
|
|
||||||
setSubscribedTopics(authorSubscriptionsTopics)
|
|
||||||
} catch (error) {
|
|
||||||
console.log('[getAuthorFollowing]', error)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!searchParams().by) {
|
if (!searchParams().by) {
|
||||||
changeSearchParam('by', 'rating')
|
changeSearchParam('by', 'rating')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sortedArticles().length === PRERENDERED_ARTICLES_COUNT) {
|
if (sortedArticles().length === PRERENDERED_ARTICLES_COUNT) {
|
||||||
await loadMore()
|
await loadMore()
|
||||||
}
|
}
|
||||||
|
@ -113,6 +115,13 @@ export const AuthorView = (props: AuthorProps) => {
|
||||||
const [commented, setCommented] = createSignal([])
|
const [commented, setCommented] = createSignal([])
|
||||||
|
|
||||||
createEffect(async () => {
|
createEffect(async () => {
|
||||||
|
if (searchParams().by === 'subscriptions') {
|
||||||
|
setIsLoaded(false)
|
||||||
|
const { authors, topics } = await fetchSubscriptions()
|
||||||
|
setSubscriptions([...authors, ...topics])
|
||||||
|
setIsLoaded(true)
|
||||||
|
}
|
||||||
|
|
||||||
if (searchParams().by === 'commented') {
|
if (searchParams().by === 'commented') {
|
||||||
try {
|
try {
|
||||||
const data = await apiClient.getReactionsBy({
|
const data = await apiClient.getReactionsBy({
|
||||||
|
@ -124,7 +133,6 @@ export const AuthorView = (props: AuthorProps) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="author-page">
|
<div class="author-page">
|
||||||
<div class="wide-container">
|
<div class="wide-container">
|
||||||
|
@ -142,14 +150,9 @@ export const AuthorView = (props: AuthorProps) => {
|
||||||
{t('Followers')}
|
{t('Followers')}
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li classList={{ selected: searchParams().by === 'subscribed-authors' }}>
|
<li classList={{ selected: searchParams().by === 'subscriptions' }}>
|
||||||
<button type="button" onClick={() => changeSearchParam('by', 'subscribed-authors')}>
|
<button type="button" onClick={() => changeSearchParam('by', 'subscriptions')}>
|
||||||
{t('Author subscriptions')}
|
{t('Subscriptions')}
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
<li classList={{ selected: searchParams().by === 'subscribed-topics' }}>
|
|
||||||
<button type="button" onClick={() => changeSearchParam('by', 'subscribed-topics')}>
|
|
||||||
{t('Topic subscriptions')}
|
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li classList={{ selected: searchParams().by === 'commented' }}>
|
<li classList={{ selected: searchParams().by === 'commented' }}>
|
||||||
|
@ -225,19 +228,6 @@ export const AuthorView = (props: AuthorProps) => {
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</Match>
|
</Match>
|
||||||
<Match when={searchParams().by === 'subscribed-topics'}>
|
|
||||||
<div class="wide-container">
|
|
||||||
<div class="row">
|
|
||||||
<For each={subscribedTopics()}>
|
|
||||||
{(topic) => (
|
|
||||||
<div class="col-md-12 col-lg-8">
|
|
||||||
<TopicCard compact iconButton isTopicInRow topic={topic} />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</For>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Match>
|
|
||||||
<Match when={searchParams().by === 'followers'}>
|
<Match when={searchParams().by === 'followers'}>
|
||||||
<div class="wide-container">
|
<div class="wide-container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
@ -251,16 +241,29 @@ export const AuthorView = (props: AuthorProps) => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Match>
|
</Match>
|
||||||
<Match when={searchParams().by === 'subscribed-authors'}>
|
<Match when={searchParams().by === 'subscriptions'}>
|
||||||
<div class="wide-container">
|
<div class="wide-container">
|
||||||
<div class="row">
|
<div class="row position-relative">
|
||||||
<For each={followingUsers()}>
|
<Show
|
||||||
{(follower: Author) => (
|
when={isLoaded()}
|
||||||
<div class="col-md-6 col-lg-4">
|
fallback={
|
||||||
<AuthorCard author={follower} hideWriteButton={true} hasLink={true} />
|
<div class={styles.loadingWrapper}>
|
||||||
|
<Loading />
|
||||||
</div>
|
</div>
|
||||||
)}
|
}
|
||||||
</For>
|
>
|
||||||
|
<For each={subscriptions()}>
|
||||||
|
{(subscription: Author | Topic) => (
|
||||||
|
<div class="col-md-24">
|
||||||
|
{isAuthor(subscription) ? (
|
||||||
|
<AuthorCard author={subscription} hideWriteButton={true} hasLink={true} />
|
||||||
|
) : (
|
||||||
|
<TopicCard compact iconButton isTopicInRow topic={subscription} />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Match>
|
</Match>
|
1
src/components/Views/Author/index.ts
Normal file
1
src/components/Views/Author/index.ts
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export { AuthorView, PRERENDERED_ARTICLES_COUNT } from './Author'
|
|
@ -1,7 +1,7 @@
|
||||||
import type { PageContext } from '../renderer/types'
|
import type { PageContext } from '../renderer/types'
|
||||||
import { apiClient } from '../utils/apiClient'
|
import { apiClient } from '../utils/apiClient'
|
||||||
import type { PageProps } from './types'
|
import type { PageProps } from './types'
|
||||||
import { PRERENDERED_ARTICLES_COUNT } from '../components/Views/Author'
|
import { PRERENDERED_ARTICLES_COUNT } from '../components/Views/Author/Author'
|
||||||
|
|
||||||
export const onBeforeRender = async (pageContext: PageContext) => {
|
export const onBeforeRender = async (pageContext: PageContext) => {
|
||||||
const { slug } = pageContext.routeParams
|
const { slug } = pageContext.routeParams
|
||||||
|
|
Loading…
Reference in New Issue
Block a user