wip-refactoring
This commit is contained in:
parent
f0f944e31a
commit
0c0084365d
|
@ -1,9 +1,9 @@
|
|||
import { PageWrap } from '../_shared/PageWrap'
|
||||
import type { PageProps } from '../types'
|
||||
import { createMemo, createSignal, For, onCleanup, onMount, Show } from 'solid-js'
|
||||
import { resetSortedArticles } from '../../stores/zine/articles'
|
||||
import { loadShoutsBy, resetSortedArticles } from '../../stores/zine/articles'
|
||||
import { useRouter } from '../../stores/router'
|
||||
import { LayoutType, loadRecentLayoutShouts, useLayoutsStore } from '../../stores/zine/layouts'
|
||||
import { LayoutType, useLayoutsStore } from '../../stores/zine/layouts'
|
||||
import { Loading } from '../Loading'
|
||||
import { restoreScrollPosition, saveScrollPosition } from '../../utils/scroll'
|
||||
import type { Shout } from '../../graphql/types.gen'
|
||||
|
@ -28,14 +28,13 @@ export const LayoutShoutsPage = (props: PageProps) => {
|
|||
return page.params.layout as LayoutType
|
||||
})
|
||||
const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false)
|
||||
const { sortedLayoutShouts } = useLayoutsStore(layout(), props.shouts)
|
||||
const { sortedLayoutShouts, loadLayoutShoutsBy } = useLayoutsStore(layout(), props.shouts)
|
||||
const sortedArticles = createMemo<Shout[]>(() => sortedLayoutShouts().get(layout()) || [])
|
||||
const loadMoreLayout = async (kind: LayoutType) => {
|
||||
saveScrollPosition()
|
||||
|
||||
const { hasMore } = await loadRecentLayoutShouts({
|
||||
layout: kind,
|
||||
amount: LOAD_MORE_PAGE_SIZE,
|
||||
const { hasMore } = await loadLayoutShoutsBy({
|
||||
by: { layout: kind },
|
||||
limit: LOAD_MORE_PAGE_SIZE,
|
||||
offset: sortedArticles().length
|
||||
})
|
||||
setIsLoadMoreButtonVisible(hasMore)
|
||||
|
@ -63,7 +62,7 @@ export const LayoutShoutsPage = (props: PageProps) => {
|
|||
|
||||
onMount(async () => {
|
||||
if (!isLoaded()) {
|
||||
await loadRecentLayoutShouts({ layout: layout(), amount: PRERENDERED_ARTICLES_COUNT, offset: 0 })
|
||||
await loadShoutsBy({ by: { layout: layout() }, limit: PRERENDERED_ARTICLES_COUNT, offset: 0 })
|
||||
}
|
||||
})
|
||||
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
import { createEffect, createSignal, Show, Suspense } from 'solid-js'
|
||||
import { FullArticle } from '../Article/FullArticle'
|
||||
import { t } from '../../utils/intl'
|
||||
import type { Shout } from '../../graphql/types.gen'
|
||||
import { loadArticleReactions, useReactionsStore } from '../../stores/zine/reactions'
|
||||
import type { Shout, Reaction } from '../../graphql/types.gen'
|
||||
import { useReactionsStore } from '../../stores/zine/reactions'
|
||||
|
||||
import '../../styles/Article.scss'
|
||||
|
||||
interface ArticlePageProps {
|
||||
article: Shout
|
||||
reactions?: Reaction[]
|
||||
}
|
||||
|
||||
const ARTICLE_COMMENTS_PAGE_SIZE = 50
|
||||
|
@ -15,13 +16,20 @@ const ARTICLE_COMMENTS_PAGE_SIZE = 50
|
|||
export const ArticleView = (props: ArticlePageProps) => {
|
||||
const [getCommentsPage] = createSignal(1)
|
||||
const [getIsCommentsLoading, setIsCommentsLoading] = createSignal(false)
|
||||
const reactionslist = useReactionsStore()
|
||||
const {
|
||||
reactionsByShout,
|
||||
sortedReactions,
|
||||
createReaction,
|
||||
updateReaction,
|
||||
deleteReaction,
|
||||
loadReactionsBy
|
||||
} = useReactionsStore({ reactions: props.reactions })
|
||||
|
||||
createEffect(async () => {
|
||||
try {
|
||||
setIsCommentsLoading(true)
|
||||
await loadArticleReactions({
|
||||
articleSlug: props.article.slug,
|
||||
await loadReactionsBy({
|
||||
by: { shout: props.article.slug },
|
||||
limit: ARTICLE_COMMENTS_PAGE_SIZE,
|
||||
offset: getCommentsPage() * ARTICLE_COMMENTS_PAGE_SIZE
|
||||
})
|
||||
|
@ -36,7 +44,7 @@ export const ArticleView = (props: ArticlePageProps) => {
|
|||
<Suspense>
|
||||
<FullArticle
|
||||
article={props.article}
|
||||
reactions={reactionslist().filter((r) => r.shout.slug === props.article.slug)}
|
||||
reactions={reactionsByShout()[props.article.slug]}
|
||||
isCommentsLoading={getIsCommentsLoading()}
|
||||
/>
|
||||
</Suspense>
|
||||
|
|
|
@ -1,56 +1,41 @@
|
|||
import { createMemo, createSignal, For, onMount, Show } from 'solid-js'
|
||||
import { createEffect, createSignal, For, onMount, Show } from 'solid-js'
|
||||
import '../../styles/Feed.scss'
|
||||
import stylesBeside from '../../components/Feed/Beside.module.scss'
|
||||
import { Icon } from '../_shared/Icon'
|
||||
import { byCreated, sortBy } from '../../utils/sortby'
|
||||
import { TopicCard } from '../Topic/Card'
|
||||
import { ArticleCard } from '../Feed/Card'
|
||||
import { AuthorCard } from '../Author/Card'
|
||||
import { t } from '../../utils/intl'
|
||||
import { FeedSidebar } from '../Feed/Sidebar'
|
||||
import CommentCard from '../Article/Comment'
|
||||
import { loadShoutsBy, useArticlesStore } from '../../stores/zine/articles'
|
||||
import { useArticlesStore } from '../../stores/zine/articles'
|
||||
import { useReactionsStore } from '../../stores/zine/reactions'
|
||||
import { useAuthorsStore } from '../../stores/zine/authors'
|
||||
import { useTopicsStore } from '../../stores/zine/topics'
|
||||
import { useTopAuthorsStore } from '../../stores/zine/topAuthors'
|
||||
import { useSession } from '../../context/session'
|
||||
import { Collab, ReactionKind, Shout } from '../../graphql/types.gen'
|
||||
import { collabs, setCollabs } from '../../stores/editor'
|
||||
|
||||
// const AUTHORSHIP_REACTIONS = [
|
||||
// ReactionKind.Accept,
|
||||
// ReactionKind.Reject,
|
||||
// ReactionKind.Propose,
|
||||
// ReactionKind.Ask
|
||||
// ]
|
||||
const AUTHORSHIP_REACTIONS = [
|
||||
ReactionKind.Accept,
|
||||
ReactionKind.Reject,
|
||||
ReactionKind.Propose,
|
||||
ReactionKind.Ask
|
||||
]
|
||||
|
||||
export const FEED_PAGE_SIZE = 20
|
||||
|
||||
export const FeedView = () => {
|
||||
// state
|
||||
const { sortedArticles } = useArticlesStore()
|
||||
const reactions = useReactionsStore()
|
||||
const { sortedArticles, loadShoutsBy } = useArticlesStore()
|
||||
const { sortedReactions: topComments, loadReactionsBy } = useReactionsStore({})
|
||||
const { sortedAuthors } = useAuthorsStore()
|
||||
const { topTopics } = useTopicsStore()
|
||||
const { topAuthors } = useTopAuthorsStore()
|
||||
const { session } = useSession()
|
||||
|
||||
const topReactions = createMemo(() => sortBy(reactions(), byCreated))
|
||||
|
||||
const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false)
|
||||
|
||||
// const expectingFocus = createMemo<Shout[]>(() => {
|
||||
// // 1 co-author notifications needs
|
||||
// // TODO: list of articles where you are co-author
|
||||
// // TODO: preload proposals
|
||||
// // TODO: (maybe?) and changes history
|
||||
// console.debug(reactions().filter((r) => r.kind in AUTHORSHIP_REACTIONS))
|
||||
//
|
||||
// // 2 community self-regulating mechanics
|
||||
// // TODO: query all new posts to be rated for publishing
|
||||
// // TODO: query all reactions where user is in authors list
|
||||
// return []
|
||||
// })
|
||||
|
||||
const loadMore = async () => {
|
||||
const { hasMore } = await loadShoutsBy({
|
||||
by: { visibility: 'community' },
|
||||
|
@ -60,8 +45,27 @@ export const FeedView = () => {
|
|||
setIsLoadMoreButtonVisible(hasMore)
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
loadMore()
|
||||
onMount(async () => {
|
||||
// load 5 recent comments overall
|
||||
await loadReactionsBy({ by: {}, limit: 5, offset: 0 })
|
||||
|
||||
// load recent shouts not only published ( visibility = community )
|
||||
await loadMore()
|
||||
|
||||
// TODO: load collabs
|
||||
// await loadCollabs()
|
||||
|
||||
// load recent editing shouts ( visibility = authors )
|
||||
const userslug = session().user.slug
|
||||
await loadShoutsBy({ by: { author: userslug, visibility: 'authors' }, limit: 15, offset: 0 })
|
||||
const collaborativeShouts = sortedArticles().filter((s: Shout, n: number, arr: Shout[]) => {
|
||||
if (s.visibility !== 'authors') {
|
||||
arr.splice(n, 1)
|
||||
return arr
|
||||
}
|
||||
})
|
||||
// load recent reactions on collabs
|
||||
await loadReactionsBy({ by: { shouts: [...collaborativeShouts], body: true }, limit: 5, offset: 0 })
|
||||
})
|
||||
|
||||
return (
|
||||
|
@ -122,7 +126,7 @@ export const FeedView = () => {
|
|||
<aside class="col-md-3">
|
||||
<section class="feed-comments">
|
||||
<h4>{t('Comments')}</h4>
|
||||
<For each={topReactions()}>
|
||||
<For each={topComments()}>
|
||||
{(comment) => <CommentCard comment={comment} compact={true} />}
|
||||
</For>
|
||||
</section>
|
||||
|
|
|
@ -9,7 +9,7 @@ if (slug.endsWith('.map')) {
|
|||
return Astro.redirect('/404')
|
||||
}
|
||||
|
||||
const article = await apiClient.loadShoutsBy({ by: { slug }, amount: 1})
|
||||
const article = await apiClient.loadShoutsBy({ by: { slug }, limit: 1})
|
||||
if (!article) {
|
||||
return Astro.redirect('/404')
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ import { initRouter } from '../../../stores/router'
|
|||
import { PRERENDERED_ARTICLES_COUNT } from '../../../components/Views/Author'
|
||||
|
||||
const slug = Astro.params.slug.toString()
|
||||
const shouts = await apiClient.loadShoutsBy({ by: { authors: [slug] } , amount: PRERENDERED_ARTICLES_COUNT })
|
||||
const shouts = await apiClient.loadShoutsBy({ by: { authors: [slug] } , limit: PRERENDERED_ARTICLES_COUNT })
|
||||
const author = await apiClient.loadAuthorsBy({ by: { slug } })
|
||||
|
||||
const { pathname, search } = Astro.url
|
||||
|
|
|
@ -6,7 +6,7 @@ import { initRouter } from '../stores/router'
|
|||
|
||||
const params: URLSearchParams = Astro.url.searchParams
|
||||
const q = params.get('q')
|
||||
const searchResults = await apiClient.loadShoutsBy({ by: { title: q, body: q }, amount: 50 })
|
||||
const searchResults = await apiClient.loadShoutsBy({ by: { title: q, body: q }, limit: 50 })
|
||||
|
||||
const { pathname, search } = Astro.url
|
||||
initRouter(pathname, search)
|
||||
|
|
|
@ -5,7 +5,7 @@ import { apiClient } from '../../utils/apiClient'
|
|||
import { PRERENDERED_ARTICLES_COUNT } from '../../components/Views/Topic'
|
||||
|
||||
const slug = Astro.params.slug?.toString() || ''
|
||||
const shouts = await apiClient.loadShoutsBy({ by: { topics: [slug] }, amount: PRERENDERED_ARTICLES_COUNT })
|
||||
const shouts = await apiClient.loadShoutsBy({ by: { topics: [slug] }, limit: PRERENDERED_ARTICLES_COUNT })
|
||||
const topic = await apiClient.getTopic({ slug })
|
||||
|
||||
import { initRouter } from '../../stores/router'
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
import type { Shout } from '../../graphql/types.gen'
|
||||
import type { Shout, ShoutsBy } from '../../graphql/types.gen'
|
||||
import { apiClient } from '../../utils/apiClient'
|
||||
import { useArticlesStore } from './articles'
|
||||
import { createSignal } from 'solid-js'
|
||||
import { byCreated } from '../../utils/sortby'
|
||||
|
||||
export type LayoutType = 'article' | 'audio' | 'video' | 'image' | 'literature'
|
||||
|
||||
|
@ -23,66 +22,29 @@ export const resetSortedLayoutShouts = () => {
|
|||
setSortedLayoutShouts(new Map())
|
||||
}
|
||||
|
||||
export const loadRecentLayoutShouts = async ({
|
||||
layout,
|
||||
amount,
|
||||
offset
|
||||
}: {
|
||||
layout: LayoutType
|
||||
amount: number
|
||||
offset?: number
|
||||
}): Promise<{ hasMore: boolean }> => {
|
||||
const layoutShouts: Shout[] = await apiClient.loadShoutsBy({ by: { layout }, amount, offset })
|
||||
const hasMore = layoutShouts.length < amount
|
||||
if (hasMore) layoutShouts.splice(-1)
|
||||
const shouts = layoutShouts.sort(byCreated)
|
||||
const { articlesByLayout } = useArticlesStore({ shouts })
|
||||
addLayoutShouts(layout, articlesByLayout()[layout])
|
||||
return { hasMore }
|
||||
}
|
||||
|
||||
export const loadTopMonthLayoutShouts = async (
|
||||
layout: LayoutType,
|
||||
amount: number,
|
||||
offset: number
|
||||
): Promise<{ hasMore: boolean }> => {
|
||||
const shouts = await apiClient.loadShoutsBy({ by: { layout, stat: 'rating', days: 30 } })
|
||||
const hasMore = shouts.length < amount
|
||||
if (hasMore) shouts.splice(-1)
|
||||
addLayoutShouts(layout, shouts)
|
||||
return { hasMore }
|
||||
}
|
||||
|
||||
export const loadTopLayoutShouts = async (
|
||||
layout: LayoutType,
|
||||
amount,
|
||||
offset
|
||||
): Promise<{ hasMore: boolean }> => {
|
||||
const shouts = await apiClient.loadShoutsBy({ by: { layout, stat: 'rating' } })
|
||||
const hasMore = shouts.length < amount
|
||||
if (hasMore) shouts.splice(-1)
|
||||
addLayoutShouts(layout, shouts)
|
||||
return { hasMore }
|
||||
}
|
||||
|
||||
export const loadShoutsSearch = async ({
|
||||
layout,
|
||||
query,
|
||||
export const loadLayoutShoutsBy = async ({
|
||||
by,
|
||||
limit,
|
||||
offset
|
||||
}: {
|
||||
layout: LayoutType
|
||||
query: string
|
||||
by: ShoutsBy
|
||||
limit?: number
|
||||
offset?: number
|
||||
}): Promise<void> => {
|
||||
const by = {
|
||||
layout: layout,
|
||||
query: query
|
||||
}): Promise<{ hasMore: boolean }> => {
|
||||
const newLayoutShouts = await apiClient.loadShoutsBy({
|
||||
by,
|
||||
limit: limit + 1,
|
||||
offset
|
||||
})
|
||||
|
||||
const hasMore = newLayoutShouts.length === limit + 1
|
||||
|
||||
if (hasMore) {
|
||||
newLayoutShouts.splice(-1)
|
||||
}
|
||||
const amount = limit
|
||||
const newLayoutShouts = await apiClient.loadShoutsBy({ by, amount, offset })
|
||||
addLayoutShouts(layout, newLayoutShouts)
|
||||
addLayoutShouts(by.layout as LayoutType, newLayoutShouts)
|
||||
|
||||
return { hasMore }
|
||||
}
|
||||
|
||||
export const useLayoutsStore = (layout: LayoutType, initialData: Shout[]) => {
|
||||
|
@ -91,6 +53,6 @@ export const useLayoutsStore = (layout: LayoutType, initialData: Shout[]) => {
|
|||
return {
|
||||
addLayoutShouts,
|
||||
sortedLayoutShouts,
|
||||
loadShoutsSearch
|
||||
loadLayoutShoutsBy
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,63 +1,52 @@
|
|||
import { atom, WritableAtom } from 'nanostores'
|
||||
import type { Reaction } from '../../graphql/types.gen'
|
||||
import { useStore } from '@nanostores/solid'
|
||||
import type { Reaction, Shout } from '../../graphql/types.gen'
|
||||
import { apiClient } from '../../utils/apiClient'
|
||||
import { reduceBy } from '../../utils/reduce'
|
||||
// import { roomConnect } from '../../utils/p2p'
|
||||
// FIXME
|
||||
import { createSignal } from 'solid-js'
|
||||
// TODO: import { roomConnect } from '../../utils/p2p'
|
||||
|
||||
export const REACTIONS_AMOUNT_PER_PAGE = 100
|
||||
const [sortedReactions, setSortedReactions] = createSignal<Reaction[]>([])
|
||||
const [reactionsByShout, setReactionsByShout] = createSignal<{ [articleSlug: string]: Reaction[] }>({})
|
||||
|
||||
let reactionsOrdered: WritableAtom<Reaction[]>
|
||||
export const reactions = atom<{ [slug: string]: Reaction[] }>({}) // by shout
|
||||
|
||||
export const useReactionsStore = (initial?: Reaction[]) => {
|
||||
if (!reactionsOrdered) {
|
||||
reactionsOrdered = atom(initial || [])
|
||||
reactionsOrdered.listen((rrr: Reaction[]) => reactions.set(reduceBy(rrr, 'shout')))
|
||||
}
|
||||
return useStore(reactionsOrdered)
|
||||
}
|
||||
|
||||
export const loadArticleReactions = async ({
|
||||
articleSlug,
|
||||
export const loadReactionsBy = async ({
|
||||
by,
|
||||
limit = REACTIONS_AMOUNT_PER_PAGE,
|
||||
offset = 0
|
||||
}: {
|
||||
articleSlug: string
|
||||
by
|
||||
limit?: number
|
||||
offset?: number
|
||||
}): Promise<void> => {
|
||||
const data = await apiClient.loadReactionsBy({ by: { shout: articleSlug }, amount: limit, offset })
|
||||
}): Promise<{ hasMore: boolean }> => {
|
||||
const data = await apiClient.loadReactionsBy({ by, limit: limit + 1, offset })
|
||||
const hasMore = data.length === limit + 1
|
||||
if (hasMore) data.splice(-1)
|
||||
// TODO: const [data, provider] = roomConnect(articleSlug, username, "reactions")
|
||||
reactionsOrdered.set(data)
|
||||
setSortedReactions(data)
|
||||
return { hasMore }
|
||||
}
|
||||
export const createReaction = async (reaction: Reaction) => {
|
||||
const { reaction: r } = await apiClient.createReaction({ reaction })
|
||||
return r
|
||||
}
|
||||
export const updateReaction = async (reaction: Reaction) => {
|
||||
const { reaction: r } = await apiClient.updateReaction({ reaction })
|
||||
return r
|
||||
}
|
||||
|
||||
export const loadReactions = async ({
|
||||
shoutSlugs,
|
||||
limit = 100,
|
||||
offset = 0
|
||||
}: {
|
||||
shoutSlugs: string[]
|
||||
limit: number
|
||||
offset: number
|
||||
}): Promise<void> => {
|
||||
const reactionsForShouts = await apiClient.loadReactionsBy({
|
||||
by: { shouts: shoutSlugs },
|
||||
amount: limit,
|
||||
offset
|
||||
})
|
||||
reactionsOrdered.set(reactionsForShouts)
|
||||
export const deleteReaction = async (reactionId: number) => {
|
||||
const resp = await apiClient.destroyReaction({ id: reactionId })
|
||||
return resp
|
||||
}
|
||||
export const useReactionsStore = (initialState: { reactions?: Reaction[] }) => {
|
||||
if (initialState.reactions) {
|
||||
setSortedReactions([...initialState.reactions])
|
||||
}
|
||||
|
||||
export const createReaction = async (reaction: Reaction) =>
|
||||
// FIXME
|
||||
reactionsOrdered.set(await apiClient.createReaction({ reaction }))
|
||||
|
||||
export const updateReaction = async (reaction: Reaction) =>
|
||||
// FIXME
|
||||
reactionsOrdered.set(await apiClient.updateReaction({ reaction }))
|
||||
|
||||
export const deleteReaction = async (reactionId: number) =>
|
||||
// FIXME
|
||||
reactionsOrdered.set(await apiClient.destroyReaction({ id: reactionId }))
|
||||
return {
|
||||
reactionsByShout,
|
||||
sortedReactions,
|
||||
createReaction,
|
||||
updateReaction,
|
||||
deleteReaction,
|
||||
loadReactionsBy
|
||||
}
|
||||
}
|
||||
|
|
|
@ -210,6 +210,14 @@ export const apiClient = {
|
|||
console.debug('[api-client] [api] create reaction mutation called')
|
||||
return response.data.createReaction
|
||||
},
|
||||
|
||||
// CUDL
|
||||
|
||||
createChat: async ({ title, members }) => {
|
||||
return await privateGraphQLClient
|
||||
.mutation(createChatQuery, { title: title, members: members })
|
||||
.toPromise()
|
||||
},
|
||||
updateReaction: async ({ reaction }) => {
|
||||
const response = await privateGraphQLClient.mutation(reactionUpdate, { reaction }).toPromise()
|
||||
|
||||
|
@ -220,16 +228,9 @@ export const apiClient = {
|
|||
|
||||
return response.data.deleteReaction
|
||||
},
|
||||
createChat: async ({ title, members }) => {
|
||||
return await privateGraphQLClient
|
||||
.mutation(createChatQuery, { title: title, members: members })
|
||||
.toPromise()
|
||||
},
|
||||
|
||||
getChats: async (payload = {}) => {
|
||||
const resp = await privateGraphQLClient.query(myChats, payload).toPromise()
|
||||
return resp.data.myChats
|
||||
},
|
||||
// LOAD BY
|
||||
|
||||
loadAuthorsBy: async ({ by, limit = 50, offset = 0 }) => {
|
||||
const resp = await publicGraphQLClient.query(authorsLoadBy, { by, limit, offset }).toPromise()
|
||||
console.debug(resp)
|
||||
|
@ -244,6 +245,14 @@ export const apiClient = {
|
|||
const resp = await publicGraphQLClient.query(reactionsLoadBy, { by, limit, offset }).toPromise()
|
||||
return resp.data.loadReactionsBy
|
||||
},
|
||||
|
||||
// inbox
|
||||
|
||||
getChats: async (payload = {}) => {
|
||||
const resp = await privateGraphQLClient.query(myChats, payload).toPromise()
|
||||
return resp.data.myChats
|
||||
},
|
||||
|
||||
getChatMessages: async ({
|
||||
chat,
|
||||
amount = 50,
|
||||
|
|
Loading…
Reference in New Issue
Block a user