Merge branch 'show_author_subscriptions' into 'dev'

Show author subscriptions

See merge request discoursio/discoursio-webapp!54
This commit is contained in:
ilia tapazukk 2023-04-22 14:36:38 +00:00
commit f8a7e98a8e
8 changed files with 139 additions and 43 deletions

View File

@ -235,5 +235,7 @@
"Bookmarks": "Bookmarks", "Bookmarks": "Bookmarks",
"Logout": "Logout", "Logout": "Logout",
"This comment has not yet been rated": "This comment has not yet been rated", "This comment has not yet been rated": "This comment has not yet been rated",
"This post has not been rated yet": "This post has not been rated yet" "This post has not been rated yet": "This post has not been rated yet",
"Author subscriptions": "Подписки на авторов",
"Topic subscriptions": "Подписки на темы"
} }

View File

@ -253,5 +253,7 @@
"Bookmarks": "Закладки", "Bookmarks": "Закладки",
"Logout": "Выход", "Logout": "Выход",
"This comment has not yet been rated": "Этот комментарий еще пока никто не оценил", "This comment has not yet been rated": "Этот комментарий еще пока никто не оценил",
"This post has not been rated yet": "Эту публикацию еще пока никто не оценил" "This post has not been rated yet": "Эту публикацию еще пока никто не оценил",
"Author subscriptions": "Подписки на авторов",
"Topic subscriptions": "Подписки на темы"
} }

View File

@ -1,5 +1,5 @@
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 } 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'
@ -19,6 +19,7 @@ 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'
type AuthorProps = { type AuthorProps = {
shouts: Shout[] shouts: Shout[]
@ -27,7 +28,17 @@ type AuthorProps = {
} }
export type AuthorPageSearchParams = { export type AuthorPageSearchParams = {
by: '' | 'viewed' | 'rating' | 'commented' | 'recent' | 'followed' | 'about' | 'popular' by:
| ''
| 'viewed'
| 'rating'
| 'commented'
| 'recent'
| 'subscribed-authors'
| 'subscribed-topics'
| 'followers'
| 'about'
| 'popular'
} }
export const PRERENDERED_ARTICLES_COUNT = 12 export const PRERENDERED_ARTICLES_COUNT = 12
@ -41,6 +52,34 @@ 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 [subscribedTopics, setSubscribedTopics] = createSignal<Topic[]>([])
onMount(async () => {
if (!props.author.slug) return
try {
const userSubscribers = await apiClient.getAuthorFollowers({ slug: props.author.slug })
setFollowers(userSubscribers)
} catch (error) {
console.log('[getAuthorFollowers]', error)
}
try {
const authorSubscriptionsUsers = await apiClient.getAuthorFollowingUsers({ slug: props.author.slug })
setFollowingUsers(authorSubscriptionsUsers)
} catch (error) {
console.log('[getAuthorFollowingUsers]', error)
}
try {
const authorSubscriptionsTopics = await apiClient.getAuthorFollowingTopics({
slug: props.author.slug
})
setSubscribedTopics(authorSubscriptionsTopics)
} catch (error) {
console.log('[getAuthorFollowing]', error)
}
})
onMount(() => { onMount(() => {
if (!searchParams().by) { if (!searchParams().by) {
@ -114,23 +153,26 @@ export const AuthorView = (props: AuthorProps) => {
{t('Publications')} {t('Publications')}
</button> </button>
</li> </li>
<li classList={{ selected: searchParams().by === 'followed' }}> <li classList={{ selected: searchParams().by === 'followers' }}>
<button type="button" onClick={() => changeSearchParam('by', 'followed')}> <button type="button" onClick={() => changeSearchParam('by', 'followers')}>
{t('Followers')} {t('Followers')}
</button> </button>
</li> </li>
<li classList={{ selected: searchParams().by === 'subscribed-authors' }}>
<button type="button" onClick={() => changeSearchParam('by', 'subscribed-authors')}>
{t('Author subscriptions')}
</button>
</li>
<li classList={{ selected: searchParams().by === 'subscribed-topics' }}>
<button type="button" onClick={() => changeSearchParam('by', 'subscribed-topics')}>
{t('Topic subscriptions')}
</button>
</li>
<li classList={{ selected: searchParams().by === 'commented' }}> <li classList={{ selected: searchParams().by === 'commented' }}>
<button type="button" onClick={() => changeSearchParam('by', 'commented')}> <button type="button" onClick={() => changeSearchParam('by', 'commented')}>
{t('Comments')} {t('Comments')}
</button> </button>
</li> </li>
{/*
<li classList={{ selected: searchParams().by === 'popular' }}>
<button type="button" onClick={() => changeSearchParam('by', 'popular')}>
Популярное
</button>
</li>
*/}
<li classList={{ selected: searchParams().by === 'about' }}> <li classList={{ selected: searchParams().by === 'about' }}>
<button type="button" onClick={() => changeSearchParam('by', 'about')}> <button type="button" onClick={() => changeSearchParam('by', 'about')}>
{t('About myself')} {t('About myself')}
@ -205,7 +247,20 @@ export const AuthorView = (props: AuthorProps) => {
</ul> </ul>
</div> </div>
</Match> </Match>
<Match when={searchParams().by === 'followed'}> <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'}>
<div class="wide-container"> <div class="wide-container">
<div class="row"> <div class="row">
<For each={followers()}> <For each={followers()}>
@ -218,6 +273,19 @@ export const AuthorView = (props: AuthorProps) => {
</div> </div>
</div> </div>
</Match> </Match>
<Match when={searchParams().by === 'subscribed-authors'}>
<div class="wide-container">
<div class="row">
<For each={followingUsers()}>
{(follower: Author) => (
<div class="col-md-6 col-lg-4">
<AuthorCard author={follower} hideWriteButton={true} hasLink={true} />
</div>
)}
</For>
</div>
</div>
</Match>
<Match when={searchParams().by === 'rating'}> <Match when={searchParams().by === 'rating'}>
<Row1 article={sortedArticles()[0]} /> <Row1 article={sortedArticles()[0]} />
<Row2 articles={sortedArticles().slice(1, 3)} isEqual={true} /> <Row2 articles={sortedArticles().slice(1, 3)} isEqual={true} />

View File

@ -0,0 +1,19 @@
import { gql } from '@urql/core'
export default gql`
query UserFollowingTopicsQuery($slug: String!) {
userFollowedTopics(slug: $slug) {
id
slug
title
body
pic
# community
stat {
shouts
followers
authors
}
}
}
`

View File

@ -0,0 +1,12 @@
import { gql } from '@urql/core'
export default gql`
query UserFollowingUsersQuery($slug: String!) {
userFollowedAuthors(slug: $slug) {
id
slug
name
userpic
}
}
`

View File

@ -1,23 +0,0 @@
import { gql } from '@urql/core'
export default gql`
query UserFollowingQuery($slug: String!) {
userFollowing(slug: $slug) {
_id: slug
id
slug
name
bio
userpic
communities
links
createdAt
lastSeen
ratings {
_id: rater
rater
value
}
}
}
`

View File

@ -196,6 +196,7 @@ export type Mutation = {
deleteReaction: Result deleteReaction: Result
deleteShout: Result deleteShout: Result
destroyTopic: Result destroyTopic: Result
draftToShout: Result
follow: Result follow: Result
getSession: AuthResult getSession: AuthResult
inviteAccept: Result inviteAccept: Result
@ -271,6 +272,10 @@ export type MutationDestroyTopicArgs = {
slug: Scalars['String'] slug: Scalars['String']
} }
export type MutationDraftToShoutArgs = {
draft: Scalars['Int']
}
export type MutationFollowArgs = { export type MutationFollowArgs = {
slug: Scalars['String'] slug: Scalars['String']
what: FollowingEntity what: FollowingEntity
@ -382,6 +387,7 @@ export type Query = {
loadShout?: Maybe<Shout> loadShout?: Maybe<Shout>
loadShouts: Array<Maybe<Shout>> loadShouts: Array<Maybe<Shout>>
markdownBody: Scalars['String'] markdownBody: Scalars['String']
myFeed?: Maybe<Array<Maybe<Shout>>>
searchMessages: Result searchMessages: Result
searchRecipients: Result searchRecipients: Result
signIn: AuthResult signIn: AuthResult
@ -447,6 +453,10 @@ export type QueryMarkdownBodyArgs = {
body: Scalars['String'] body: Scalars['String']
} }
export type QueryMyFeedArgs = {
options?: InputMaybe<LoadShoutsOptions>
}
export type QuerySearchMessagesArgs = { export type QuerySearchMessagesArgs = {
by: MessagesBy by: MessagesBy
limit?: InputMaybe<Scalars['Int']> limit?: InputMaybe<Scalars['Int']>
@ -573,6 +583,7 @@ export type Result = {
chats?: Maybe<Array<Maybe<Chat>>> chats?: Maybe<Array<Maybe<Chat>>>
communities?: Maybe<Array<Maybe<Community>>> communities?: Maybe<Array<Maybe<Community>>>
community?: Maybe<Community> community?: Maybe<Community>
draft?: Maybe<DraftCollab>
drafts?: Maybe<Array<Maybe<DraftCollab>>> drafts?: Maybe<Array<Maybe<DraftCollab>>>
error?: Maybe<Scalars['String']> error?: Maybe<Scalars['String']>
members?: Maybe<Array<Maybe<ChatMember>>> members?: Maybe<Array<Maybe<ChatMember>>>
@ -610,7 +621,6 @@ export type Shout = {
mainTopic?: Maybe<Scalars['String']> mainTopic?: Maybe<Scalars['String']>
media?: Maybe<Scalars['String']> media?: Maybe<Scalars['String']>
publishedAt?: Maybe<Scalars['DateTime']> publishedAt?: Maybe<Scalars['DateTime']>
publishedBy?: Maybe<User>
slug: Scalars['String'] slug: Scalars['String']
stat?: Maybe<Stat> stat?: Maybe<Stat>
subtitle?: Maybe<Scalars['String']> subtitle?: Maybe<Scalars['String']>
@ -675,7 +685,8 @@ export type Token = {
export type Topic = { export type Topic = {
body?: Maybe<Scalars['String']> body?: Maybe<Scalars['String']>
community: Community community?: Community
id: Scalars['Int']
oid?: Maybe<Scalars['String']> oid?: Maybe<Scalars['String']>
pic?: Maybe<Scalars['String']> pic?: Maybe<Scalars['String']>
slug: Scalars['String'] slug: Scalars['String']

View File

@ -38,7 +38,8 @@ import myChats from '../graphql/query/chats-load'
import chatMessagesLoadBy from '../graphql/query/chat-messages-load-by' import chatMessagesLoadBy from '../graphql/query/chat-messages-load-by'
import authorBySlug from '../graphql/query/author-by-slug' import authorBySlug from '../graphql/query/author-by-slug'
import userSubscribers from '../graphql/query/author-followers' import userSubscribers from '../graphql/query/author-followers'
import userFollowing from '../graphql/query/author-following' import userFollowedAuthors from '../graphql/query/author-following-users'
import userFollowedTopics from '../graphql/query/author-following-topics'
import topicBySlug from '../graphql/query/topic-by-slug' import topicBySlug from '../graphql/query/topic-by-slug'
import createChat from '../graphql/mutation/create-chat' import createChat from '../graphql/mutation/create-chat'
import reactionsLoadBy from '../graphql/query/reactions-load-by' import reactionsLoadBy from '../graphql/query/reactions-load-by'
@ -222,9 +223,13 @@ export const apiClient = {
const response = await publicGraphQLClient.query(userSubscribers, { slug }).toPromise() const response = await publicGraphQLClient.query(userSubscribers, { slug }).toPromise()
return response.data.userFollowers return response.data.userFollowers
}, },
getAuthorFollowing: async ({ slug }: { slug: string }): Promise<Author[]> => { getAuthorFollowingUsers: async ({ slug }: { slug: string }): Promise<Author[]> => {
const response = await publicGraphQLClient.query(userFollowing, { slug }).toPromise() const response = await publicGraphQLClient.query(userFollowedAuthors, { slug }).toPromise()
return response.data.userFollowing return response.data.userFollowedAuthors
},
getAuthorFollowingTopics: async ({ slug }: { slug: string }): Promise<Topic[]> => {
const response = await publicGraphQLClient.query(userFollowedTopics, { slug }).toPromise()
return response.data.userFollowedTopics
}, },
updateProfile: async (input: ProfileInput) => { updateProfile: async (input: ProfileInput) => {
const response = await privateGraphQLClient.mutation(updateProfile, { profile: input }).toPromise() const response = await privateGraphQLClient.mutation(updateProfile, { profile: input }).toPromise()