webapp/src/stores/zine/articles.ts

221 lines
5.3 KiB
TypeScript
Raw Normal View History

import type { Author, Shout, LoadShoutsOptions } from '../../graphql/types.gen'
import { createLazyMemo } from '@solid-primitives/memo'
import { createSignal } from 'solid-js'
2022-09-09 11:53:35 +00:00
import { apiClient } from '../../utils/apiClient'
import { getServerDate } from '../../utils/getServerDate'
2022-09-13 09:59:04 +00:00
import { byStat } from '../../utils/sortby'
import { addAuthorsByTopic } from './authors'
2022-09-22 09:37:49 +00:00
2022-09-28 20:16:44 +00:00
const [sortedArticles, setSortedArticles] = createSignal<Shout[]>([])
const [articleEntities, setArticleEntities] = createSignal<{ [articleSlug: string]: Shout }>({})
2022-09-09 11:53:35 +00:00
2022-09-28 20:16:44 +00:00
const [topArticles, setTopArticles] = createSignal<Shout[]>([])
const [topMonthArticles, setTopMonthArticles] = createSignal<Shout[]>([])
2022-09-22 09:37:49 +00:00
2022-09-29 17:37:21 +00:00
const articlesByAuthor = createLazyMemo(() => {
return Object.values(articleEntities()).reduce(
(acc, article) => {
article.authors.forEach((author) => {
if (!acc[author.slug]) {
acc[author.slug] = []
}
acc[author.slug].push(article)
})
2022-09-13 09:59:04 +00:00
return acc
},
{} as { [authorSlug: string]: Shout[] },
)
2022-09-28 20:16:44 +00:00
})
2022-09-13 09:59:04 +00:00
2022-09-29 17:37:21 +00:00
const articlesByTopic = createLazyMemo(() => {
return Object.values(articleEntities()).reduce(
(acc, article) => {
article.topics.forEach((topic) => {
if (!acc[topic.slug]) {
acc[topic.slug] = []
}
acc[topic.slug].push(article)
})
2022-09-13 09:59:04 +00:00
return acc
},
{} as { [authorSlug: string]: Shout[] },
)
2022-09-28 20:16:44 +00:00
})
2022-09-13 09:59:04 +00:00
2022-09-29 17:37:21 +00:00
const topViewedArticles = createLazyMemo(() => {
2022-09-28 20:16:44 +00:00
const result = Object.values(articleEntities())
result.sort(byStat('viewed'))
return result
})
2022-09-13 09:59:04 +00:00
2022-09-29 17:37:21 +00:00
const topCommentedArticles = createLazyMemo(() => {
2022-09-28 20:16:44 +00:00
const result = Object.values(articleEntities())
result.sort(byStat('commented'))
return result
})
2022-09-09 11:53:35 +00:00
// eslint-disable-next-line sonarjs/cognitive-complexity
2022-09-13 09:59:04 +00:00
const addArticles = (...args: Shout[][]) => {
const allArticles = args.flatMap((articles) => articles || [])
const newArticleEntities = allArticles.reduce(
(acc, article) => {
acc[article.slug] = article
return acc
},
{} as { [articleSLug: string]: Shout },
)
2022-09-09 11:53:35 +00:00
2022-09-28 20:16:44 +00:00
setArticleEntities((prevArticleEntities) => {
return {
...prevArticleEntities,
...newArticleEntities,
2022-09-28 20:16:44 +00:00
}
})
2022-09-09 11:53:35 +00:00
const authorsByTopic = allArticles.reduce(
(acc, article) => {
const { authors, topics } = article
2022-09-13 09:59:04 +00:00
topics.forEach((topic) => {
if (!acc[topic.slug]) {
acc[topic.slug] = []
2022-09-13 09:59:04 +00:00
}
authors.forEach((author) => {
if (!acc[topic.slug].some((a) => a.slug === author.slug)) {
acc[topic.slug].push(author)
}
})
2022-09-09 11:53:35 +00:00
})
2022-09-13 09:59:04 +00:00
return acc
},
{} as { [topicSlug: string]: Author[] },
)
2022-09-13 09:59:04 +00:00
addAuthorsByTopic(authorsByTopic)
}
const addSortedArticles = (articles: Shout[]) => {
2022-09-22 09:37:49 +00:00
setSortedArticles((prevSortedArticles) => [...prevSortedArticles, ...articles])
2022-09-09 11:53:35 +00:00
}
2022-11-18 02:23:04 +00:00
export const loadShout = async (slug: string): Promise<void> => {
2023-05-08 17:21:06 +00:00
const newArticle = await apiClient.getShoutBySlug(slug)
2023-11-04 13:40:55 +00:00
if (!newArticle) {
return
}
2022-11-18 02:23:04 +00:00
addArticles([newArticle])
2023-02-28 17:13:14 +00:00
const newArticleIndex = sortedArticles().findIndex((s) => s.id === newArticle.id)
if (newArticleIndex >= 0) {
const newSortedArticles = [...sortedArticles()]
newSortedArticles[newArticleIndex] = newArticle
setSortedArticles(newSortedArticles)
}
2022-11-18 02:23:04 +00:00
}
2023-02-28 17:13:14 +00:00
export const loadShouts = async (
options: LoadShoutsOptions,
2023-02-28 17:13:14 +00:00
): Promise<{ hasMore: boolean; newShouts: Shout[] }> => {
const newShouts = await apiClient.getShouts({
2022-11-18 02:23:04 +00:00
...options,
limit: options.limit + 1,
})
2023-02-28 17:13:14 +00:00
const hasMore = newShouts.length === options.limit + 1
if (hasMore) {
2023-02-28 17:13:14 +00:00
newShouts.splice(-1)
}
2023-02-28 17:13:14 +00:00
addArticles(newShouts)
addSortedArticles(newShouts)
2023-02-28 17:13:14 +00:00
return { hasMore, newShouts }
2022-10-05 15:11:14 +00:00
}
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 }
}
2022-10-05 15:11:14 +00:00
export const resetSortedArticles = () => {
setSortedArticles([])
}
2022-09-09 11:53:35 +00:00
type InitialState = {
2022-11-15 14:24:50 +00:00
shouts?: Shout[]
2022-09-09 11:53:35 +00:00
}
const TOP_MONTH_ARTICLES_COUNT = 10
export const loadTopMonthArticles = async (): Promise<void> => {
const now = new Date()
const fromDate = getServerDate(new Date(now.setMonth(now.getMonth() - 1)))
const articles = await apiClient.getShouts({
filters: {
visibility: 'public',
fromDate,
},
order_by: 'rating_stat',
limit: TOP_MONTH_ARTICLES_COUNT,
})
addArticles(articles)
setTopMonthArticles(articles)
}
const TOP_ARTICLES_COUNT = 10
export const loadTopArticles = async (): Promise<void> => {
const articles = await apiClient.getShouts({
filters: {
visibility: 'public',
},
order_by: 'rating_stat',
limit: TOP_ARTICLES_COUNT,
})
addArticles(articles)
setTopArticles(articles)
}
2022-09-23 07:38:48 +00:00
export const useArticlesStore = (initialState: InitialState = {}) => {
2022-11-15 14:24:50 +00:00
addArticles([...(initialState.shouts || [])])
2022-09-09 12:18:09 +00:00
2022-11-15 14:24:50 +00:00
if (initialState.shouts) {
setSortedArticles([...initialState.shouts])
2022-09-13 09:59:04 +00:00
}
2022-09-09 12:18:09 +00:00
2022-09-13 09:59:04 +00:00
return {
2022-09-28 20:16:44 +00:00
articleEntities,
sortedArticles,
articlesByAuthor,
2022-11-15 14:24:50 +00:00
articlesByTopic,
2022-09-28 20:16:44 +00:00
topMonthArticles,
2022-11-15 14:24:50 +00:00
topArticles,
2022-09-28 20:16:44 +00:00
topCommentedArticles,
topViewedArticles,
2022-09-13 09:59:04 +00:00
}
2022-09-09 12:18:09 +00:00
}