One page with subscriptions to authors and topics (#99)

* One page with subscriptions to authors and topics

* resolve conversation
This commit is contained in:
Ilya Y 2023-05-17 13:41:50 +03:00 committed by GitHub
parent c60b7e5c53
commit afcebb10b1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 81 additions and 73 deletions

View File

@ -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",

View File

@ -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": "Попробуйте найти по-другому",

View File

@ -71,3 +71,11 @@
} }
} }
} }
.loadingWrapper {
position: relative;
min-height: 40vh;
display: flex;
align-items: center;
justify-content: center;
}

View File

@ -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>

View File

@ -0,0 +1 @@
export { AuthorView, PRERENDERED_ARTICLES_COUNT } from './Author'

View File

@ -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