webapp/src/stores/zine/topics.ts

141 lines
3.8 KiB
TypeScript
Raw Normal View History

2022-09-09 11:53:35 +00:00
import { apiClient } from '../../utils/apiClient'
2022-09-22 09:37:49 +00:00
import { map, MapStore, ReadableAtom, atom, computed } from 'nanostores'
2022-09-09 11:53:35 +00:00
import type { Topic } from '../../graphql/types.gen'
import { useStore } from '@nanostores/solid'
2022-09-22 09:37:49 +00:00
import { byCreated, byTopicStatDesc } from '../../utils/sortby'
import { getLogger } from '../../utils/logger'
import { createSignal } from 'solid-js'
2022-09-09 11:53:35 +00:00
2022-09-22 09:37:49 +00:00
const log = getLogger('topics store')
2022-09-09 11:53:35 +00:00
2022-09-22 09:37:49 +00:00
export type TopicsSortBy = 'created' | 'title' | 'authors' | 'shouts'
const sortAllByStore = atom<TopicsSortBy>('shouts')
2022-09-09 11:53:35 +00:00
2022-09-16 07:45:56 +00:00
let topicEntitiesStore: MapStore<Record<string, Topic>>
2022-09-09 11:53:35 +00:00
let sortedTopicsStore: ReadableAtom<Topic[]>
2022-09-13 09:59:04 +00:00
let topTopicsStore: ReadableAtom<Topic[]>
2022-09-22 09:37:49 +00:00
const [getRandomTopics, setRandomTopics] = createSignal<Topic[]>()
2022-09-16 07:45:56 +00:00
let topicsByAuthorStore: MapStore<Record<string, Topic[]>>
2022-09-09 11:53:35 +00:00
2022-09-22 09:37:49 +00:00
const initStore = (initial?: { [topicSlug: string]: Topic }) => {
2022-09-09 11:53:35 +00:00
if (topicEntitiesStore) {
return
}
2022-09-16 07:45:56 +00:00
topicEntitiesStore = map<Record<string, Topic>>(initial)
2022-09-09 11:53:35 +00:00
2022-09-13 13:38:26 +00:00
sortedTopicsStore = computed([topicEntitiesStore, sortAllByStore], (topicEntities, sortBy) => {
2022-09-09 11:53:35 +00:00
const topics = Object.values(topicEntities)
switch (sortBy) {
case 'created': {
2022-09-22 09:37:49 +00:00
// log.debug('sorted by created')
2022-09-09 11:53:35 +00:00
topics.sort(byCreated)
break
}
2022-09-22 09:37:49 +00:00
case 'shouts':
case 'authors':
// log.debug(`sorted by ${sortBy}`)
topics.sort(byTopicStatDesc(sortBy))
break
case 'title':
// log.debug('sorted by title')
topics.sort((a, b) => a.title.localeCompare(b.title))
break
default:
log.error(`Unknown sort: ${sortBy}`)
2022-09-09 11:53:35 +00:00
}
return topics
})
2022-09-13 09:59:04 +00:00
topTopicsStore = computed(topicEntitiesStore, (topicEntities) => {
const topics = Object.values(topicEntities)
2022-09-22 09:37:49 +00:00
topics.sort(byTopicStatDesc('shouts'))
2022-09-13 09:59:04 +00:00
return topics
})
2022-09-09 11:53:35 +00:00
}
2022-09-22 09:37:49 +00:00
export const setSortAllTopicsBy = (sortBy: TopicsSortBy) => {
if (sortAllByStore.get() !== sortBy) {
sortAllByStore.set(sortBy)
}
2022-09-13 13:38:26 +00:00
}
2022-09-13 09:59:04 +00:00
const addTopics = (...args: Topic[][]) => {
const allTopics = args.flatMap((topics) => topics || [])
const newTopicEntities = allTopics.reduce((acc, topic) => {
2022-09-09 11:53:35 +00:00
acc[topic.slug] = topic
return acc
}, {} as Record<string, Topic>)
if (!topicEntitiesStore) {
initStore(newTopicEntities)
} else {
topicEntitiesStore.set({
...topicEntitiesStore.get(),
...newTopicEntities
})
}
}
2022-09-13 09:59:04 +00:00
export const addTopicsByAuthor = (topicsByAuthors: { [authorSlug: string]: Topic[] }) => {
const allTopics = Object.values(topicsByAuthors).flat()
addTopics(allTopics)
if (!topicsByAuthorStore) {
2022-09-16 07:45:56 +00:00
topicsByAuthorStore = map<Record<string, Topic[]>>(topicsByAuthors)
2022-09-13 09:59:04 +00:00
} else {
const newState = Object.entries(topicsByAuthors).reduce((acc, [authorSlug, topics]) => {
if (!acc[authorSlug]) {
acc[authorSlug] = []
}
topics.forEach((topic) => {
if (!acc[authorSlug].some((t) => t.slug === topic.slug)) {
acc[authorSlug].push(topic)
}
})
return acc
}, topicsByAuthorStore.get())
topicsByAuthorStore.set(newState)
}
}
2022-09-09 11:53:35 +00:00
export const loadAllTopics = async (): Promise<void> => {
const topics = await apiClient.getAllTopics()
addTopics(topics)
}
type InitialState = {
topics?: Topic[]
randomTopics?: Topic[]
2022-09-22 09:37:49 +00:00
sortBy?: TopicsSortBy
2022-09-09 11:53:35 +00:00
}
2022-09-23 07:38:48 +00:00
export const useTopicsStore = (initialState: InitialState = {}) => {
const topics = [...(initialState.topics || [])]
const randomTopics = [...(initialState.randomTopics || [])]
if (initialState.sortBy) {
sortAllByStore.set(initialState.sortBy)
2022-09-16 07:45:56 +00:00
}
2022-09-22 09:37:49 +00:00
addTopics(topics, randomTopics)
2022-09-16 07:45:56 +00:00
if (randomTopics) {
2022-09-22 09:37:49 +00:00
setRandomTopics(randomTopics)
2022-09-13 09:59:04 +00:00
}
2022-09-09 11:53:35 +00:00
const getTopicEntities = useStore(topicEntitiesStore)
2022-09-22 09:37:49 +00:00
2022-09-09 11:53:35 +00:00
const getSortedTopics = useStore(sortedTopicsStore)
2022-09-22 09:37:49 +00:00
2022-09-13 09:59:04 +00:00
const getTopTopics = useStore(topTopicsStore)
2022-09-13 08:05:11 +00:00
2022-09-22 09:37:49 +00:00
return { getTopicEntities, getSortedTopics, getRandomTopics, getTopTopics }
2022-09-09 11:53:35 +00:00
}