diff --git a/src/components/Views/Home.tsx b/src/components/Views/Home.tsx index a7b69137..43e2a0bf 100644 --- a/src/components/Views/Home.tsx +++ b/src/components/Views/Home.tsx @@ -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(null) + const [randomTopicArticles, setRandomTopicArticles] = createSignal([]) + 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 ( - - - - ) + 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={

{t('Top commented')}

} nodate={true} /> - {randomLayout()} + + + diff --git a/src/graphql/query/articles-load-random-topic.ts b/src/graphql/query/articles-load-random-topic.ts new file mode 100644 index 00000000..b6bc8a39 --- /dev/null +++ b/src/graphql/query/articles-load-random-topic.ts @@ -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 + } + } + } + } +` diff --git a/src/graphql/types.gen.ts b/src/graphql/types.gen.ts index 609977af..60674764 100644 --- a/src/graphql/types.gen.ts +++ b/src/graphql/types.gen.ts @@ -373,6 +373,7 @@ export type Query = { loadMySubscriptions?: Maybe loadNotifications: NotificationsQueryResult loadRandomTopShouts: Array> + loadRandomTopicShouts: RandomTopicShoutsQueryResult loadReactionsBy: Array> loadRecipients: Result loadShout?: Maybe @@ -430,6 +431,10 @@ export type QueryLoadRandomTopShoutsArgs = { params?: InputMaybe } +export type QueryLoadRandomTopicShoutsArgs = { + limit: Scalars['Int']['input'] +} + export type QueryLoadReactionsByArgs = { by: ReactionBy limit?: InputMaybe @@ -504,6 +509,11 @@ export type QueryUserFollowersArgs = { slug: Scalars['String']['input'] } +export type RandomTopicShoutsQueryResult = { + shouts: Array> + topic: Topic +} + export type Rating = { rater: Scalars['String']['output'] value: Scalars['Int']['output'] diff --git a/src/stores/zine/articles.ts b/src/stores/zine/articles.ts index e8fd9842..721aca2b 100644 --- a/src/stores/zine/articles.ts +++ b/src/stores/zine/articles.ts @@ -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, diff --git a/src/utils/apiClient.ts b/src/utils/apiClient.ts index 01430f7b..eacbd655 100644 --- a/src/utils/apiClient.ts +++ b/src/utils/apiClient.ts @@ -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 => { const resp = await graphQLClient.query(articlesLoadUnrated, { limit }).toPromise() if (resp.error) {