random topic (#343)

* test

* test

* index random topic

---------

Co-authored-by: Igor Lobanov <igor.lobanov@onetwotrip.com>
This commit is contained in:
Igor Lobanov 2023-12-21 00:59:16 +01:00 committed by GitHub
parent 4a2f95aa55
commit d113d9ca8a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 102 additions and 44 deletions

View File

@ -1,6 +1,6 @@
import type { Shout } from '../../graphql/types.gen'
import type { Shout, Topic } from '../../graphql/types.gen'
import { createMemo, createSignal, For, onMount, Show } from 'solid-js'
import { batch, createMemo, createSignal, For, onMount, Show } from 'solid-js'
import { useLocalize } from '../../context/localize'
import {
@ -11,6 +11,7 @@ import {
} from '../../stores/zine/articles'
import { useTopAuthorsStore } from '../../stores/zine/topAuthors'
import { useTopicsStore } from '../../stores/zine/topics'
import { apiClient } from '../../utils/apiClient'
import { restoreScrollPosition, saveScrollPosition } from '../../utils/scroll'
import { splitToPages } from '../../utils/splitToPages'
import { ArticleCardSwiper } from '../_shared/SolidSwiper/ArticleCardSwiper'
@ -31,26 +32,24 @@ type Props = {
export const PRERENDERED_ARTICLES_COUNT = 5
export const RANDOM_TOPICS_COUNT = 12
export const RANDOM_TOPIC_SHOUTS_COUNT = 7
const CLIENT_LOAD_ARTICLES_COUNT = 29
const LOAD_MORE_PAGE_SIZE = 16 // Row1 + Row3 + Row2 + Beside (3 + 1) + Row1 + Row 2 + Row3
export const HomeView = (props: Props) => {
const {
sortedArticles,
articlesByLayout,
topArticles,
topCommentedArticles,
topMonthArticles,
topViewedArticles,
} = useArticlesStore({
shouts: props.shouts,
})
const { sortedArticles, topArticles, topCommentedArticles, topMonthArticles, topViewedArticles } =
useArticlesStore({
shouts: props.shouts,
})
const { topTopics } = useTopicsStore()
const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false)
const { topAuthors } = useTopAuthorsStore()
const { t } = useLocalize()
const [randomTopic, setRandomTopic] = createSignal<Topic>(null)
const [randomTopicArticles, setRandomTopicArticles] = createSignal<Shout[]>([])
onMount(async () => {
loadTopArticles()
loadTopMonthArticles()
@ -63,22 +62,12 @@ export const HomeView = (props: Props) => {
setIsLoadMoreButtonVisible(hasMore)
}
})
const randomLayout = createMemo(() => {
const filledLayouts = Object.keys(articlesByLayout()).filter(
// FIXME: is 7 ok? or more complex logic needed?
(layout) => articlesByLayout()[layout].length > 7,
)
const selectedRandomLayout =
filledLayouts.length > 0 ? filledLayouts[Math.floor(Math.random() * filledLayouts.length)] : ''
return (
<Show when={Boolean(selectedRandomLayout)}>
<Group articles={articlesByLayout()[selectedRandomLayout]} header={''} />
</Show>
)
const { topic, shouts } = await apiClient.getRandomTopicShouts(RANDOM_TOPIC_SHOUTS_COUNT)
batch(() => {
setRandomTopic(topic)
setRandomTopicArticles(shouts)
})
})
const loadMore = async () => {
@ -135,7 +124,9 @@ export const HomeView = (props: Props) => {
header={<h2>{t('Top commented')}</h2>}
nodate={true}
/>
{randomLayout()}
<Show when={randomTopic()}>
<Group articles={randomTopicArticles()} header={''} />
</Show>
<Show when={topArticles()}>
<ArticleCardSwiper title={t('Favorite')} slides={topArticles()} />
</Show>

View File

@ -0,0 +1,62 @@
import { gql } from '@urql/core'
export default gql`
query LoadRandomTopicShoutsQuery($limit: Int!) {
loadRandomTopicShouts(limit: $limit) {
topic {
id
title
body
slug
pic
# community
stat {
shouts
authors
followers
# viewed
}
}
shouts {
id
title
lead
description
subtitle
slug
layout
cover
lead
# community
mainTopic
topics {
id
title
body
slug
stat {
shouts
authors
followers
}
}
authors {
id
name
slug
userpic
createdAt
bio
}
createdAt
publishedAt
stat {
viewed
reacted
rating
commented
}
}
}
}
`

View File

@ -373,6 +373,7 @@ export type Query = {
loadMySubscriptions?: Maybe<MySubscriptionsQueryResult>
loadNotifications: NotificationsQueryResult
loadRandomTopShouts: Array<Maybe<Shout>>
loadRandomTopicShouts: RandomTopicShoutsQueryResult
loadReactionsBy: Array<Maybe<Reaction>>
loadRecipients: Result
loadShout?: Maybe<Shout>
@ -430,6 +431,10 @@ export type QueryLoadRandomTopShoutsArgs = {
params?: InputMaybe<LoadRandomTopShoutsParams>
}
export type QueryLoadRandomTopicShoutsArgs = {
limit: Scalars['Int']['input']
}
export type QueryLoadReactionsByArgs = {
by: ReactionBy
limit?: InputMaybe<Scalars['Int']['input']>
@ -504,6 +509,11 @@ export type QueryUserFollowersArgs = {
slug: Scalars['String']['input']
}
export type RandomTopicShoutsQueryResult = {
shouts: Array<Maybe<Shout>>
topic: Topic
}
export type Rating = {
rater: Scalars['String']['output']
value: Scalars['Int']['output']

View File

@ -47,21 +47,6 @@ const articlesByTopic = createLazyMemo(() => {
)
})
const articlesByLayout = createLazyMemo(() => {
return Object.values(articleEntities()).reduce(
(acc, article) => {
if (!acc[article.layout]) {
acc[article.layout] = []
}
acc[article.layout].push(article)
return acc
},
{} as { [layout: string]: Shout[] },
)
})
const topViewedArticles = createLazyMemo(() => {
const result = Object.values(articleEntities())
result.sort(byStat('viewed'))
@ -226,7 +211,6 @@ export const useArticlesStore = (initialState: InitialState = {}) => {
articleEntities,
sortedArticles,
articlesByAuthor,
articlesByLayout,
articlesByTopic,
topMonthArticles,
topArticles,

View File

@ -44,6 +44,7 @@ import updateProfile from '../graphql/mutation/update-profile'
import shoutLoad from '../graphql/query/article-load'
import shoutsLoadBy from '../graphql/query/articles-load-by'
import articlesLoadRandomTop from '../graphql/query/articles-load-random-top'
import articlesLoadRandomTopic from '../graphql/query/articles-load-random-topic'
import articlesLoadUnrated from '../graphql/query/articles-load-unrated'
import authCheckEmailQuery from '../graphql/query/auth-check-email'
import authLoginQuery from '../graphql/query/auth-login'
@ -359,6 +360,16 @@ export const apiClient = {
return resp.data.loadRandomTopShouts
},
getRandomTopicShouts: async (limit: number): Promise<{ topic: Topic; shouts: Shout[] }> => {
const resp = await graphQLClient.query(articlesLoadRandomTopic, { limit }).toPromise()
if (resp.error) {
console.error(resp)
}
return resp.data.loadRandomTopicShouts
},
getUnratedShouts: async (limit: number): Promise<Shout[]> => {
const resp = await graphQLClient.query(articlesLoadUnrated, { limit }).toPromise()
if (resp.error) {