Feature/feed (#118)
* feed pages, feed sidebar, styles cleanup * my feed page * Restore feed sidebar style * Minor fix * Editor style fixes * feed sort * code review --------- Co-authored-by: kvakazyambra <kvakazyambra@gmail.com>
This commit is contained in:
parent
dc9888b0f1
commit
5d2b944a64
|
@ -57,6 +57,11 @@ const pagesMap: Record<keyof typeof ROUTES, Component<PageProps>> = {
|
|||
authors: AllAuthorsPage,
|
||||
author: AuthorPage,
|
||||
feed: FeedPage,
|
||||
feedMy: FeedPage,
|
||||
feedNotifications: FeedPage,
|
||||
feedBookmarks: FeedPage,
|
||||
feedCollaborations: FeedPage,
|
||||
feedDiscussions: FeedPage,
|
||||
article: ArticlePage,
|
||||
search: SearchPage,
|
||||
discussionRules: DiscussionRulesPage,
|
||||
|
|
|
@ -16,8 +16,13 @@
|
|||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.selected {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.counter {
|
||||
@include font-size(1.2rem);
|
||||
|
||||
align-items: center;
|
||||
align-self: flex-start;
|
||||
background: #f6f6f6;
|
||||
|
|
|
@ -10,23 +10,18 @@ import { useLocalize } from '../../../context/localize'
|
|||
import styles from './Sidebar.module.scss'
|
||||
import { clsx } from 'clsx'
|
||||
import Userpic from '../../Author/Userpic'
|
||||
import { getPagePath } from '@nanostores/router'
|
||||
import { router, useRouter } from '../../../stores/router'
|
||||
|
||||
type FeedSidebarProps = {
|
||||
authors: Author[]
|
||||
}
|
||||
|
||||
type ListItem = {
|
||||
title: string
|
||||
icon?: string
|
||||
counter?: number
|
||||
href?: string
|
||||
isBold?: boolean
|
||||
}
|
||||
|
||||
export const Sidebar = (props: FeedSidebarProps) => {
|
||||
const { t } = useLocalize()
|
||||
const { seen } = useSeenStore()
|
||||
const { session } = useSession()
|
||||
const { page } = useRouter()
|
||||
const { authorEntities } = useAuthorsStore({ authors: props.authors })
|
||||
const { articlesByTopic } = useArticlesStore()
|
||||
const { topicEntities } = useTopicsStore()
|
||||
|
@ -40,68 +35,87 @@ export const Sidebar = (props: FeedSidebarProps) => {
|
|||
return Boolean(seen()[authorSlug])
|
||||
}
|
||||
|
||||
const menuItems: ListItem[] = [
|
||||
{
|
||||
icon: 'feed-all',
|
||||
title: t('general feed')
|
||||
},
|
||||
{
|
||||
icon: 'feed-my',
|
||||
title: t('My feed')
|
||||
},
|
||||
{
|
||||
icon: 'feed-collaborate',
|
||||
title: t('Accomplices')
|
||||
},
|
||||
{
|
||||
icon: 'feed-discussion',
|
||||
title: t('Discussions'),
|
||||
counter: 4
|
||||
},
|
||||
{
|
||||
icon: 'feed-drafts',
|
||||
title: t('Drafts'),
|
||||
counter: 14
|
||||
},
|
||||
{
|
||||
icon: 'bookmark',
|
||||
title: t('Bookmarks'),
|
||||
counter: 6
|
||||
},
|
||||
{
|
||||
icon: 'feed-notifications',
|
||||
title: t('Notifications')
|
||||
}
|
||||
]
|
||||
|
||||
return (
|
||||
<div class={styles.sidebar}>
|
||||
<ul>
|
||||
<For each={menuItems}>
|
||||
{(item: ListItem, index) => (
|
||||
<li>
|
||||
{/* TODO: implement selection logic */}
|
||||
<Show when={index() === 0}>
|
||||
<strong>
|
||||
<span class={styles.sidebarItemName}>
|
||||
{item.icon && <Icon name={item.icon} class={styles.icon} />}
|
||||
{item.title}
|
||||
</span>
|
||||
{item.counter && <span class={styles.counter}>18</span>}
|
||||
</strong>
|
||||
</Show>
|
||||
<Show when={index() > 0}>
|
||||
<a href="#">
|
||||
<span class={styles.sidebarItemName}>
|
||||
{item.icon && <Icon name={item.icon} class={styles.icon} />}
|
||||
{item.title}
|
||||
</span>
|
||||
{item.counter && <span class={styles.counter}>18</span>}
|
||||
</a>
|
||||
</Show>
|
||||
</li>
|
||||
)}
|
||||
</For>
|
||||
<li>
|
||||
<a
|
||||
href={getPagePath(router, 'feed')}
|
||||
class={clsx({
|
||||
[styles.selected]: page().route === 'feed'
|
||||
})}
|
||||
>
|
||||
<span class={styles.sidebarItemName}>
|
||||
<Icon name="feed-all" class={styles.icon} />
|
||||
{t('general feed')}
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href={getPagePath(router, 'feedMy')}
|
||||
class={clsx({
|
||||
[styles.selected]: page().route === 'feedMy'
|
||||
})}
|
||||
>
|
||||
<span class={styles.sidebarItemName}>
|
||||
<Icon name="feed-my" class={styles.icon} />
|
||||
{t('My feed')}
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href={getPagePath(router, 'feedCollaborations')}
|
||||
class={clsx({
|
||||
[styles.selected]: page().route === 'feedCollaborations'
|
||||
})}
|
||||
>
|
||||
<span class={styles.sidebarItemName}>
|
||||
<Icon name="feed-collaborate" class={styles.icon} />
|
||||
{t('Accomplices')}
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href={getPagePath(router, 'feedDiscussions')}
|
||||
class={clsx({
|
||||
[styles.selected]: page().route === 'feedDiscussions'
|
||||
})}
|
||||
>
|
||||
<span class={styles.sidebarItemName}>
|
||||
<Icon name="feed-discussion" class={styles.icon} />
|
||||
{t('Discussions')}
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href={getPagePath(router, 'feedBookmarks')}
|
||||
class={clsx({
|
||||
[styles.selected]: page().route === 'feedBookmarks'
|
||||
})}
|
||||
>
|
||||
<span class={styles.sidebarItemName}>
|
||||
<Icon name="bookmark" class={styles.icon} />
|
||||
{t('Bookmarks')}
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href={getPagePath(router, 'feedNotifications')}
|
||||
class={clsx({
|
||||
[styles.selected]: page().route === 'feedNotifications'
|
||||
})}
|
||||
>
|
||||
<span class={styles.sidebarItemName}>
|
||||
<Icon name="feed-notifications" class={styles.icon} />
|
||||
{t('Notifications')}
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<Show when={session()?.news?.authors || session()?.news?.topics}>
|
||||
|
|
|
@ -25,11 +25,6 @@ type Props = {
|
|||
export const Header = (props: Props) => {
|
||||
const { t } = useLocalize()
|
||||
|
||||
const resources: { name: string; route: keyof typeof ROUTES }[] = [
|
||||
{ name: t('zine'), route: 'home' },
|
||||
{ name: t('feed'), route: 'feed' },
|
||||
{ name: t('topics'), route: 'topics' }
|
||||
]
|
||||
// signals
|
||||
const [getIsScrollingBottom, setIsScrollingBottom] = createSignal(false)
|
||||
const [getIsScrolled, setIsScrolled] = createSignal(false)
|
||||
|
@ -112,13 +107,15 @@ export const Header = (props: Props) => {
|
|||
<div class={styles.articleHeader}>{props.title}</div>
|
||||
</Show>
|
||||
<ul class={clsx('view-switcher', styles.mainNavigation)} classList={{ fixed: fixed() }}>
|
||||
<For each={resources}>
|
||||
{(r) => (
|
||||
<li classList={{ 'view-switcher__item--selected': r.route === page().route }}>
|
||||
<a href={getPagePath(router, r.route)}>{r.name}</a>
|
||||
</li>
|
||||
)}
|
||||
</For>
|
||||
<li classList={{ 'view-switcher__item--selected': page().route === 'home' }}>
|
||||
<a href={getPagePath(router, 'home')}>{t('zine')}</a>
|
||||
</li>
|
||||
<li classList={{ 'view-switcher__item--selected': page().route.startsWith('feed') }}>
|
||||
<a href={getPagePath(router, 'feed')}>{t('feed')}</a>
|
||||
</li>
|
||||
<li classList={{ 'view-switcher__item--selected': page().route === 'topics' }}>
|
||||
<a href={getPagePath(router, 'topics')}>{t('topics')}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<HeaderAuth setIsProfilePopupVisible={setIsProfilePopupVisible} />
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
|
||||
.topic {
|
||||
@include font-size(1.2rem);
|
||||
|
||||
background: transparentize(#2638d9, 0.95);
|
||||
display: inline-block;
|
||||
font-weight: bold;
|
||||
|
@ -91,44 +92,39 @@
|
|||
|
||||
ul {
|
||||
@include font-size(1.4rem);
|
||||
|
||||
font-weight: bold;
|
||||
margin: 1rem 0 0;
|
||||
line-height: 1.3;
|
||||
|
||||
li {
|
||||
margin-bottom: 1.6rem;
|
||||
padding-left: 3.4rem;
|
||||
margin-bottom: 1.2rem;
|
||||
padding-left: 2.6rem;
|
||||
position: relative;
|
||||
|
||||
&::before {
|
||||
background: url(/icons/knowledge-base-bullet.svg) no-repeat;
|
||||
content: '';
|
||||
height: 1.6rem;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
width: 2rem;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
a:link {
|
||||
a {
|
||||
border: none;
|
||||
|
||||
&::before {
|
||||
background: url(/public/icons/knowledge-base-bullet.svg) no-repeat;
|
||||
content: '';
|
||||
height: 2.4rem;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
top: -0.1em;
|
||||
width: 2.4rem;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
&:before {
|
||||
background-image: url(/public/icons/knowledge-base-bullet-hover.svg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.comment {
|
||||
@include font-size(1.5rem);
|
||||
|
||||
line-height: 1.4;
|
||||
margin-bottom: 2.4rem;
|
||||
|
||||
|
@ -149,6 +145,7 @@
|
|||
|
||||
.commentBody {
|
||||
@include font-size(1.4rem);
|
||||
|
||||
margin-bottom: 1.2rem;
|
||||
line-clamp: 3;
|
||||
-webkit-line-clamp: 3;
|
||||
|
@ -175,5 +172,6 @@
|
|||
.commentArticleTitle,
|
||||
.commentAuthor {
|
||||
@include font-size(1.2rem);
|
||||
|
||||
font-weight: 500;
|
||||
}
|
||||
|
|
|
@ -1,35 +1,52 @@
|
|||
import { createEffect, createSignal, For, onMount, Show } from 'solid-js'
|
||||
import { createEffect, createSignal, For, on, onMount, Show } from 'solid-js'
|
||||
import { Icon } from '../_shared/Icon'
|
||||
import { ArticleCard } from '../Feed/ArticleCard'
|
||||
import { AuthorCard } from '../Author/AuthorCard'
|
||||
import { Sidebar } from '../Feed/Sidebar'
|
||||
import { loadShouts, useArticlesStore } from '../../stores/zine/articles'
|
||||
import { loadShouts, loadMyFeed, useArticlesStore, resetSortedArticles } from '../../stores/zine/articles'
|
||||
import { useAuthorsStore } from '../../stores/zine/authors'
|
||||
import { useTopicsStore } from '../../stores/zine/topics'
|
||||
import { useTopAuthorsStore } from '../../stores/zine/topAuthors'
|
||||
import { useSession } from '../../context/session'
|
||||
import { clsx } from 'clsx'
|
||||
import { useReactions } from '../../context/reactions'
|
||||
import type { Author, Reaction } from '../../graphql/types.gen'
|
||||
import type { Author, LoadShoutsOptions, Reaction } from '../../graphql/types.gen'
|
||||
import { getPagePath } from '@nanostores/router'
|
||||
import { router } from '../../stores/router'
|
||||
import { router, useRouter } from '../../stores/router'
|
||||
import { useLocalize } from '../../context/localize'
|
||||
import styles from './Feed.module.scss'
|
||||
import stylesTopic from '../Feed/CardTopic.module.scss'
|
||||
import stylesBeside from '../../components/Feed/Beside.module.scss'
|
||||
import { CommentDate } from '../Article/CommentDate'
|
||||
import { Loading } from '../_shared/Loading'
|
||||
|
||||
export const FEED_PAGE_SIZE = 20
|
||||
|
||||
type FeedSearchParams = {
|
||||
by: 'publish_date' | 'rating' | 'last_comment'
|
||||
}
|
||||
|
||||
const getOrderBy = (by: FeedSearchParams['by']) => {
|
||||
if (by === 'rating') {
|
||||
return 'rating_stat'
|
||||
}
|
||||
|
||||
if (by === 'last_comment') {
|
||||
return 'last_comment'
|
||||
}
|
||||
|
||||
return ''
|
||||
}
|
||||
|
||||
export const FeedView = () => {
|
||||
const { t } = useLocalize()
|
||||
const { page, searchParams } = useRouter<FeedSearchParams>()
|
||||
const [isLoading, setIsLoading] = createSignal(false)
|
||||
|
||||
// state
|
||||
const { sortedArticles } = useArticlesStore()
|
||||
const { sortedAuthors } = useAuthorsStore()
|
||||
const { topTopics } = useTopicsStore()
|
||||
const { topAuthors } = useTopAuthorsStore()
|
||||
const { session, user } = useSession()
|
||||
const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false)
|
||||
const [topComments, setTopComments] = createSignal<Reaction[]>([])
|
||||
|
||||
|
@ -37,30 +54,43 @@ export const FeedView = () => {
|
|||
actions: { loadReactionsBy }
|
||||
} = useReactions()
|
||||
|
||||
// TODO:
|
||||
// const collaborativeShouts = createMemo(() =>
|
||||
// sortedArticles().filter((shout) => shout.visibility === 'authors')
|
||||
// )
|
||||
createEffect(
|
||||
on(
|
||||
() => page().route + searchParams().by,
|
||||
() => {
|
||||
resetSortedArticles()
|
||||
loadMore()
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
// createEffect(async () => {
|
||||
// if (collaborativeShouts()) {
|
||||
// await loadReactionsBy({ by: { shouts: collaborativeShouts().map((shout) => shout.slug) }, limit: 5 })
|
||||
// }
|
||||
// })
|
||||
|
||||
createEffect(async () => {
|
||||
if (user()) {
|
||||
// load recent editing shouts ( visibility = authors )
|
||||
await loadShouts({ filters: { author: user().slug, visibility: 'authors' }, limit: 15 })
|
||||
}
|
||||
})
|
||||
|
||||
const loadMore = async () => {
|
||||
const { hasMore, newShouts } = await loadShouts({
|
||||
filters: { visibility: 'community' },
|
||||
const loadFeedShouts = () => {
|
||||
const options: LoadShoutsOptions = {
|
||||
limit: FEED_PAGE_SIZE,
|
||||
offset: sortedArticles().length
|
||||
}
|
||||
|
||||
const orderBy = getOrderBy(searchParams().by)
|
||||
|
||||
if (orderBy) {
|
||||
options.order_by = orderBy
|
||||
}
|
||||
|
||||
if (page().route === 'feedMy') {
|
||||
return loadMyFeed(options)
|
||||
}
|
||||
|
||||
// default feed
|
||||
return loadShouts({
|
||||
...options,
|
||||
filters: { visibility: 'community' }
|
||||
})
|
||||
}
|
||||
|
||||
const loadMore = async () => {
|
||||
setIsLoading(true)
|
||||
const { hasMore, newShouts } = await loadFeedShouts()
|
||||
setIsLoading(false)
|
||||
|
||||
loadReactionsBy({
|
||||
by: {
|
||||
|
@ -72,8 +102,6 @@ export const FeedView = () => {
|
|||
}
|
||||
|
||||
onMount(async () => {
|
||||
// load recent shouts not only published ( visibility = community )
|
||||
await loadMore()
|
||||
// load 5 recent comments overall
|
||||
const comments = await loadReactionsBy({ by: { comment: true }, limit: 5 })
|
||||
setTopComments(comments)
|
||||
|
@ -89,62 +117,75 @@ export const FeedView = () => {
|
|||
|
||||
<div class="col-md-12 offset-xl-1">
|
||||
<ul class={clsx(styles.feedFilter, 'view-switcher')}>
|
||||
<Show when={!!session()?.user?.slug}>
|
||||
<li class="view-switcher__item--selected">
|
||||
<a href="/feed/my">{t('My feed')}</a>
|
||||
</li>
|
||||
</Show>
|
||||
<li>
|
||||
<a href="/feed/?by=views">{t('Most read')}</a>
|
||||
<li
|
||||
class={clsx({
|
||||
'view-switcher__item--selected':
|
||||
searchParams().by === 'publish_date' || !searchParams().by
|
||||
})}
|
||||
>
|
||||
<a href={getPagePath(router, page().route)}>{t('My feed')}</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/feed/?by=rating">{t('Top rated')}</a>
|
||||
{/*<li>*/}
|
||||
{/* <a href="/feed/?by=views">{t('Most read')}</a>*/}
|
||||
{/*</li>*/}
|
||||
<li
|
||||
class={clsx({
|
||||
'view-switcher__item--selected': searchParams().by === 'rating'
|
||||
})}
|
||||
>
|
||||
<a href={`${getPagePath(router, page().route)}?by=rating`}>{t('Top rated')}</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/feed/?by=comments">{t('Most commented')}</a>
|
||||
<li
|
||||
class={clsx({
|
||||
'view-switcher__item--selected': searchParams().by === 'last_comment'
|
||||
})}
|
||||
>
|
||||
<a href={`${getPagePath(router, page().route)}?by=last_comment`}>{t('Most commented')}</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<Show when={sortedArticles().length > 0}>
|
||||
<For each={sortedArticles().slice(0, 4)}>
|
||||
{(article) => <ArticleCard article={article} settings={{ isFeedMode: true }} />}
|
||||
</For>
|
||||
|
||||
<div class={stylesBeside.besideColumnTitle}>
|
||||
<h4>{t('Popular authors')}</h4>
|
||||
<a href="/authors">
|
||||
{t('All authors')}
|
||||
<Icon name="arrow-right" class={stylesBeside.icon} />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<ul class={stylesBeside.besideColumn}>
|
||||
<For each={topAuthors().slice(0, 5)}>
|
||||
{(author) => (
|
||||
<li>
|
||||
<AuthorCard
|
||||
author={author}
|
||||
hideWriteButton={true}
|
||||
hasLink={true}
|
||||
truncateBio={true}
|
||||
isTextButton={true}
|
||||
/>
|
||||
</li>
|
||||
)}
|
||||
<Show when={!isLoading()} fallback={<Loading />}>
|
||||
<Show when={sortedArticles().length > 0}>
|
||||
<For each={sortedArticles().slice(0, 4)}>
|
||||
{(article) => <ArticleCard article={article} settings={{ isFeedMode: true }} />}
|
||||
</For>
|
||||
</ul>
|
||||
|
||||
<For each={sortedArticles().slice(4)}>
|
||||
{(article) => <ArticleCard article={article} settings={{ isFeedMode: true }} />}
|
||||
</For>
|
||||
</Show>
|
||||
<div class={stylesBeside.besideColumnTitle}>
|
||||
<h4>{t('Popular authors')}</h4>
|
||||
<a href="/authors">
|
||||
{t('All authors')}
|
||||
<Icon name="arrow-right" class={stylesBeside.icon} />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<Show when={isLoadMoreButtonVisible()}>
|
||||
<p class="load-more-container">
|
||||
<button class="button" onClick={loadMore}>
|
||||
{t('Load more')}
|
||||
</button>
|
||||
</p>
|
||||
<ul class={stylesBeside.besideColumn}>
|
||||
<For each={topAuthors().slice(0, 5)}>
|
||||
{(author) => (
|
||||
<li>
|
||||
<AuthorCard
|
||||
author={author}
|
||||
hideWriteButton={true}
|
||||
hasLink={true}
|
||||
truncateBio={true}
|
||||
isTextButton={true}
|
||||
/>
|
||||
</li>
|
||||
)}
|
||||
</For>
|
||||
</ul>
|
||||
|
||||
<For each={sortedArticles().slice(4)}>
|
||||
{(article) => <ArticleCard article={article} settings={{ isFeedMode: true }} />}
|
||||
</For>
|
||||
</Show>
|
||||
|
||||
<Show when={isLoadMoreButtonVisible()}>
|
||||
<p class="load-more-container">
|
||||
<button class="button" onClick={loadMore}>
|
||||
{t('Load more')}
|
||||
</button>
|
||||
</p>
|
||||
</Show>
|
||||
</Show>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -12,15 +12,10 @@ export default gql`
|
|||
# community
|
||||
mainTopic
|
||||
topics {
|
||||
# id
|
||||
id
|
||||
title
|
||||
body
|
||||
slug
|
||||
stat {
|
||||
shouts
|
||||
authors
|
||||
followers
|
||||
}
|
||||
}
|
||||
authors {
|
||||
id
|
||||
|
|
4
src/pages/feedMy.page.route.ts
Normal file
4
src/pages/feedMy.page.route.ts
Normal file
|
@ -0,0 +1,4 @@
|
|||
import { ROUTES } from '../stores/router'
|
||||
import { getServerRoute } from '../utils/getServerRoute'
|
||||
|
||||
export default getServerRoute(ROUTES.feedMy)
|
|
@ -16,6 +16,11 @@ export const ROUTES = {
|
|||
authors: '/authors',
|
||||
author: '/author/:slug',
|
||||
feed: '/feed',
|
||||
feedMy: '/feed/my',
|
||||
feedNotifications: '/feed/notifications',
|
||||
feedDiscussions: '/feed/discussions',
|
||||
feedBookmarks: '/feed/bookmarks',
|
||||
feedCollaborations: '/feed/collaborations',
|
||||
search: '/search/:q?',
|
||||
article: '/:slug',
|
||||
dogma: '/about/dogma',
|
||||
|
|
|
@ -154,6 +154,26 @@ export const loadShouts = async (
|
|||
return { hasMore, newShouts }
|
||||
}
|
||||
|
||||
export const loadMyFeed = async (
|
||||
options: LoadShoutsOptions
|
||||
): Promise<{ hasMore: boolean; newShouts: Shout[] }> => {
|
||||
const newShouts = await apiClient.getMyFeed({
|
||||
...options,
|
||||
limit: options.limit + 1
|
||||
})
|
||||
|
||||
const hasMore = newShouts.length === options.limit + 1
|
||||
|
||||
if (hasMore) {
|
||||
newShouts.splice(-1)
|
||||
}
|
||||
|
||||
addArticles(newShouts)
|
||||
addSortedArticles(newShouts)
|
||||
|
||||
return { hasMore, newShouts }
|
||||
}
|
||||
|
||||
export const resetSortedArticles = () => {
|
||||
setSortedArticles([])
|
||||
}
|
||||
|
|
|
@ -48,6 +48,7 @@ import authorsLoadBy from '../graphql/query/authors-load-by'
|
|||
import shoutsLoadBy from '../graphql/query/articles-load-by'
|
||||
import draftsLoad from '../graphql/query/drafts-load'
|
||||
import shoutLoad from '../graphql/query/article-load'
|
||||
import myFeed from '../graphql/query/my-feed'
|
||||
import loadRecipients from '../graphql/query/chat-recipients'
|
||||
import createMessage from '../graphql/mutation/create-chat-message'
|
||||
import updateProfile from '../graphql/mutation/update-profile'
|
||||
|
@ -330,6 +331,16 @@ export const apiClient = {
|
|||
return resp.data.loadShouts
|
||||
},
|
||||
|
||||
getMyFeed: async (options: LoadShoutsOptions) => {
|
||||
const resp = await privateGraphQLClient.query(myFeed, { options }).toPromise()
|
||||
|
||||
if (resp.error) {
|
||||
console.error(resp)
|
||||
}
|
||||
|
||||
return resp.data.myFeed
|
||||
},
|
||||
|
||||
getReactionsBy: async ({ by, limit }: { by: ReactionBy; limit?: number }) => {
|
||||
const resp = await publicGraphQLClient
|
||||
.query(reactionsLoadBy, { by, limit: limit ?? 1000, offset: 0 })
|
||||
|
|
Loading…
Reference in New Issue
Block a user