webapp/src/stores/zine/topics.ts

124 lines
3.5 KiB
TypeScript
Raw Normal View History

2022-09-09 11:53:35 +00:00
import { apiClient } from '../../utils/apiClient'
import type { ReadableAtom, WritableAtom } from 'nanostores'
import { atom, computed } from 'nanostores'
import type { Topic } from '../../graphql/types.gen'
import { useStore } from '@nanostores/solid'
2022-09-13 09:59:04 +00:00
import { byCreated, byStat } from '../../utils/sortby'
2022-09-13 13:38:26 +00:00
import type { AuthorsSortBy } from './authors'
2022-09-09 11:53:35 +00:00
export type TopicsSortBy = 'created' | 'name'
2022-09-13 13:38:26 +00:00
const sortAllByStore = atom<TopicsSortBy>('created')
2022-09-09 11:53:35 +00:00
2022-09-13 09:59:04 +00:00
let topicEntitiesStore: WritableAtom<{ [topicSlug: 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[]>
let randomTopicsStore: WritableAtom<Topic[]>
let topicsByAuthorStore: WritableAtom<{ [authorSlug: string]: Topic[] }>
2022-09-09 11:53:35 +00:00
const initStore = (initial?: Record<string, Topic>) => {
if (topicEntitiesStore) {
return
}
topicEntitiesStore = atom<Record<string, Topic>>(initial)
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': {
topics.sort(byCreated)
break
}
// eslint-disable-next-line unicorn/no-useless-switch-case
case 'name':
default: {
// use default sorting abc stores
console.debug('[topics.store] default sort')
}
}
return topics
})
2022-09-13 09:59:04 +00:00
topTopicsStore = computed(topicEntitiesStore, (topicEntities) => {
const topics = Object.values(topicEntities)
// DISCUSS
// topics.sort(byStat('shouts'))
topics.sort(byStat('rating'))
return topics
})
2022-09-09 11:53:35 +00:00
}
2022-09-13 13:38:26 +00:00
export const setSortAllBy = (sortBy: TopicsSortBy) => {
sortAllByStore.set(sortBy)
}
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) {
topicsByAuthorStore = atom<{ [authorSlug: string]: Topic[] }>(topicsByAuthors)
} 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-13 09:59:04 +00:00
export const useTopicsStore = ({ topics, randomTopics }: InitialState = {}) => {
addTopics(topics, randomTopics)
if (!randomTopicsStore) {
randomTopicsStore = atom(randomTopics)
}
2022-09-09 11:53:35 +00:00
const getTopicEntities = useStore(topicEntitiesStore)
const getSortedTopics = useStore(sortedTopicsStore)
2022-09-13 09:59:04 +00:00
const getRandomTopics = useStore(randomTopicsStore)
const getTopicsByAuthor = useStore(topicsByAuthorStore)
const getTopTopics = useStore(topTopicsStore)
2022-09-13 08:05:11 +00:00
2022-09-13 09:59:04 +00:00
return { getTopicEntities, getSortedTopics, getRandomTopics, getTopicsByAuthor, getTopTopics }
2022-09-09 11:53:35 +00:00
}