author-feed-debug
This commit is contained in:
parent
1a9529d9fc
commit
01e7dec615
8
.vscode/launch.json
vendored
8
.vscode/launch.json
vendored
|
@ -1,16 +1,14 @@
|
||||||
{
|
{
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
|
|
||||||
{
|
{
|
||||||
"name": "Launch Brave against localhost",
|
"name": "Launch browser against localhost",
|
||||||
"type": "chrome",
|
"type": "chrome",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"url": "http://localhost:3000",
|
"url": "https://localhost:3000",
|
||||||
"webRoot": "${workspaceFolder}/src",
|
"webRoot": "${workspaceFolder}/src",
|
||||||
"sourceMaps": true,
|
"sourceMaps": true,
|
||||||
"trace": true,
|
"trace": true
|
||||||
"runtimeExecutable": "/Applications/Brave Browser.app/Contents/MacOS/Brave Browser"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
import { For, Show, createMemo, createSignal, lazy, onMount } from 'solid-js'
|
import { For, Show, createMemo, createSignal, lazy, onMount } from 'solid-js'
|
||||||
|
|
||||||
import { useFeed } from '~/context/feed'
|
import { useFeed } from '~/context/feed'
|
||||||
import { useLocalize } from '~/context/localize'
|
import { useLocalize } from '~/context/localize'
|
||||||
import { useReactions } from '~/context/reactions'
|
import { COMMENTS_PER_PAGE, useReactions } from '~/context/reactions'
|
||||||
import { useSession } from '~/context/session'
|
import { useSession } from '~/context/session'
|
||||||
import {
|
import {
|
||||||
QueryLoad_Reactions_ByArgs,
|
|
||||||
Reaction,
|
Reaction,
|
||||||
ReactionKind,
|
ReactionKind,
|
||||||
ReactionSort,
|
ReactionSort,
|
||||||
|
@ -26,12 +24,11 @@ const SimplifiedEditor = lazy(() => import('../Editor/SimplifiedEditor'))
|
||||||
type Props = {
|
type Props = {
|
||||||
shout: Shout
|
shout: Shout
|
||||||
}
|
}
|
||||||
const COMMENTS_PER_PAGE = 50
|
|
||||||
|
|
||||||
export const CommentsTree = (props: Props) => {
|
export const CommentsTree = (props: Props) => {
|
||||||
const { session } = useSession()
|
const { session } = useSession()
|
||||||
const { t } = useLocalize()
|
const { t } = useLocalize()
|
||||||
const { reactionEntities, createReaction, loadReactionsBy, addReactions } = useReactions()
|
const { reactionEntities, createReaction, loadShoutComments } = useReactions()
|
||||||
const { seen } = useFeed()
|
const { seen } = useFeed()
|
||||||
const [commentsOrder, setCommentsOrder] = createSignal<ReactionSort>(ReactionSort.Newest)
|
const [commentsOrder, setCommentsOrder] = createSignal<ReactionSort>(ReactionSort.Newest)
|
||||||
const [onlyNew, setOnlyNew] = createSignal(false)
|
const [onlyNew, setOnlyNew] = createSignal(false)
|
||||||
|
@ -83,13 +80,7 @@ export const CommentsTree = (props: Props) => {
|
||||||
setCommentsLoading(true)
|
setCommentsLoading(true)
|
||||||
const next = pagination() + 1
|
const next = pagination() + 1
|
||||||
const offset = next * COMMENTS_PER_PAGE
|
const offset = next * COMMENTS_PER_PAGE
|
||||||
const opts: QueryLoad_Reactions_ByArgs = {
|
const rrr = await loadShoutComments(props.shout.id, COMMENTS_PER_PAGE, offset)
|
||||||
by: { comment: true, shout: props.shout.slug },
|
|
||||||
limit: COMMENTS_PER_PAGE,
|
|
||||||
offset
|
|
||||||
}
|
|
||||||
const rrr = await loadReactionsBy(opts)
|
|
||||||
rrr && addReactions(rrr)
|
|
||||||
rrr && setPagination(next)
|
rrr && setPagination(next)
|
||||||
setCommentsLoading(false)
|
setCommentsLoading(false)
|
||||||
return rrr as LoadMoreItems
|
return rrr as LoadMoreItems
|
||||||
|
|
|
@ -3,10 +3,10 @@ import { clsx } from 'clsx'
|
||||||
import { Show, createEffect, createMemo, createSignal, on } from 'solid-js'
|
import { Show, createEffect, createMemo, createSignal, on } from 'solid-js'
|
||||||
import { byCreated } from '~/lib/sort'
|
import { byCreated } from '~/lib/sort'
|
||||||
import { useLocalize } from '../../context/localize'
|
import { useLocalize } from '../../context/localize'
|
||||||
import { useReactions } from '../../context/reactions'
|
import { RATINGS_PER_PAGE, useReactions } from '../../context/reactions'
|
||||||
import { useSession } from '../../context/session'
|
import { useSession } from '../../context/session'
|
||||||
import { useSnackbar } from '../../context/ui'
|
import { useSnackbar } from '../../context/ui'
|
||||||
import { QueryLoad_Reactions_ByArgs, Reaction, ReactionKind, Shout } from '../../graphql/schema/core.gen'
|
import { Reaction, ReactionKind, Shout } from '../../graphql/schema/core.gen'
|
||||||
import { Icon } from '../_shared/Icon'
|
import { Icon } from '../_shared/Icon'
|
||||||
import { InlineLoader } from '../_shared/InlineLoader'
|
import { InlineLoader } from '../_shared/InlineLoader'
|
||||||
import { LoadMoreItems, LoadMoreWrapper } from '../_shared/LoadMoreWrapper'
|
import { LoadMoreItems, LoadMoreWrapper } from '../_shared/LoadMoreWrapper'
|
||||||
|
@ -26,8 +26,7 @@ export const RatingControl = (props: RatingControlProps) => {
|
||||||
const [_, changeSearchParams] = useSearchParams()
|
const [_, changeSearchParams] = useSearchParams()
|
||||||
const snackbar = useSnackbar()
|
const snackbar = useSnackbar()
|
||||||
const { session } = useSession()
|
const { session } = useSession()
|
||||||
const { addReactions } = useReactions()
|
const { reactionEntities, reactionsByShout, createReaction, deleteReaction, loadShoutRatings, loadCommentRatings } =
|
||||||
const { reactionEntities, reactionsByShout, createReaction, deleteReaction, loadReactionsBy } =
|
|
||||||
useReactions()
|
useReactions()
|
||||||
const [myRate, setMyRate] = createSignal<Reaction | undefined>()
|
const [myRate, setMyRate] = createSignal<Reaction | undefined>()
|
||||||
const [ratingReactions, setRatingReactions] = createSignal<Reaction[]>([])
|
const [ratingReactions, setRatingReactions] = createSignal<Reaction[]>([])
|
||||||
|
@ -70,12 +69,13 @@ export const RatingControl = (props: RatingControlProps) => {
|
||||||
// rating change
|
// rating change
|
||||||
const handleRatingChange = async (isUpvote: boolean) => {
|
const handleRatingChange = async (isUpvote: boolean) => {
|
||||||
setIsLoading(true)
|
setIsLoading(true)
|
||||||
|
let error = ''
|
||||||
try {
|
try {
|
||||||
if (isUpvoted()) {
|
if (isUpvoted() && isUpvote) return
|
||||||
await deleteRating(ReactionKind.Like)
|
if (isDownvoted() && !isUpvote) return
|
||||||
} else if (isDownvoted()) {
|
if (isUpvoted() && !isUpvote) error = (await deleteRating(ReactionKind.Like))?.error || ''
|
||||||
await deleteRating(ReactionKind.Dislike)
|
if (isDownvoted() && isUpvote) error = (await deleteRating(ReactionKind.Dislike))?.error || ''
|
||||||
} else {
|
if (!(isUpvoted() || isDownvoted())) {
|
||||||
props.comment?.shout.id &&
|
props.comment?.shout.id &&
|
||||||
(await createReaction({
|
(await createReaction({
|
||||||
reaction: {
|
reaction: {
|
||||||
|
@ -85,13 +85,8 @@ export const RatingControl = (props: RatingControlProps) => {
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
} catch {
|
} catch(err) {
|
||||||
snackbar?.showSnackbar({ type: 'error', body: t('Error') })
|
snackbar?.showSnackbar({ type: 'error', body: `${t('Error')}: ${error || err || ''}` })
|
||||||
}
|
|
||||||
|
|
||||||
if (props.comment?.shout.slug) {
|
|
||||||
const rrr = await loadReactionsBy({ by: { shout: props.comment.shout.slug } })
|
|
||||||
addReactions(rrr)
|
|
||||||
}
|
}
|
||||||
setIsLoading(false)
|
setIsLoading(false)
|
||||||
}
|
}
|
||||||
|
@ -138,16 +133,12 @@ export const RatingControl = (props: RatingControlProps) => {
|
||||||
: []
|
: []
|
||||||
)
|
)
|
||||||
const loadMoreReactions = async () => {
|
const loadMoreReactions = async () => {
|
||||||
|
if (!(props.shout?.id || props.comment?.id)) return [] as LoadMoreItems
|
||||||
setRatingLoading(true)
|
setRatingLoading(true)
|
||||||
const next = ratingPage() + 1
|
const next = ratingPage() + 1
|
||||||
const offset = VOTERS_PER_PAGE * next
|
const offset = RATINGS_PER_PAGE * next
|
||||||
const opts: QueryLoad_Reactions_ByArgs = {
|
const loader = props.comment ? loadCommentRatings : loadShoutRatings
|
||||||
by: { rating: true, shout: props.shout?.slug },
|
const rrr = await loader(props.shout?.id || 0, RATINGS_PER_PAGE, offset)
|
||||||
limit: VOTERS_PER_PAGE,
|
|
||||||
offset
|
|
||||||
}
|
|
||||||
const rrr = await loadReactionsBy(opts)
|
|
||||||
rrr && addReactions(rrr)
|
|
||||||
rrr && setRatingPage(next)
|
rrr && setRatingPage(next)
|
||||||
setRatingLoading(false)
|
setRatingLoading(false)
|
||||||
return rrr as LoadMoreItems
|
return rrr as LoadMoreItems
|
||||||
|
|
|
@ -61,7 +61,7 @@ export const AuthorView = (props: AuthorViewProps) => {
|
||||||
on(
|
on(
|
||||||
[() => session()?.user?.app_data?.profile, () => props.authorSlug || ''],
|
[() => session()?.user?.app_data?.profile, () => props.authorSlug || ''],
|
||||||
async ([me, slug]) => {
|
async ([me, slug]) => {
|
||||||
console.debug('check if my profile')
|
console.debug('[AuthorView] checking if my profile')
|
||||||
const my = slug && me?.slug === slug
|
const my = slug && me?.slug === slug
|
||||||
if (my) {
|
if (my) {
|
||||||
console.debug('[Author] my profile precached')
|
console.debug('[Author] my profile precached')
|
||||||
|
@ -86,7 +86,7 @@ export const AuthorView = (props: AuthorViewProps) => {
|
||||||
() => authorsEntities()[props.author?.slug || props.authorSlug || ''],
|
() => authorsEntities()[props.author?.slug || props.authorSlug || ''],
|
||||||
async (found) => {
|
async (found) => {
|
||||||
if (!found) return
|
if (!found) return
|
||||||
setAuthor(found)
|
console.debug('[AuthorView] ')
|
||||||
console.info(`[Author] profile for @${found.slug} fetched`)
|
console.info(`[Author] profile for @${found.slug} fetched`)
|
||||||
const followsResp = await query(getAuthorFollowsQuery, { slug: found.slug }).toPromise()
|
const followsResp = await query(getAuthorFollowsQuery, { slug: found.slug }).toPromise()
|
||||||
const follows = followsResp?.data?.get_author_followers || {}
|
const follows = followsResp?.data?.get_author_followers || {}
|
||||||
|
@ -96,6 +96,7 @@ export const AuthorView = (props: AuthorViewProps) => {
|
||||||
setFollowers(followersResp?.data?.get_author_followers || [])
|
setFollowers(followersResp?.data?.get_author_followers || [])
|
||||||
console.info(`[Author] followers for @${found.slug} fetched`)
|
console.info(`[Author] followers for @${found.slug} fetched`)
|
||||||
setIsFetching(false)
|
setIsFetching(false)
|
||||||
|
setTimeout(() => setAuthor(found), 1)
|
||||||
},
|
},
|
||||||
{ defer: true }
|
{ defer: true }
|
||||||
)
|
)
|
||||||
|
@ -123,7 +124,37 @@ export const AuthorView = (props: AuthorViewProps) => {
|
||||||
(tab) => tab && console.log('[views.Author] profile tab switched')
|
(tab) => tab && console.log('[views.Author] profile tab switched')
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
const AuthorFeed = () => (
|
||||||
|
<Show when={Array.isArray(props.shouts) && props.shouts.length > 0 && props.shouts[0]}>
|
||||||
|
<Row1 article={props.shouts?.[0] as Shout} noauthor={true} nodate={true} />
|
||||||
|
|
||||||
|
<Show when={props.shouts?.length || 0}>
|
||||||
|
<Show when={props.shouts?.length === 1}>
|
||||||
|
<Row1 article={props.shouts?.[0] as Shout} noauthor={true} nodate={true} />
|
||||||
|
</Show>
|
||||||
|
<Show when={props.shouts?.length === 2}>
|
||||||
|
<Row2 articles={props.shouts as Shout[]} isEqual={true} noauthor={true} nodate={true} />
|
||||||
|
</Show>
|
||||||
|
<Show when={props.shouts?.length === 3}>
|
||||||
|
<Row3 articles={props.shouts as Shout[]} noauthor={true} nodate={true} />
|
||||||
|
</Show>
|
||||||
|
<Show when={props.shouts && props.shouts.length > 3}>
|
||||||
|
<For each={pages()}>
|
||||||
|
{(page) => (
|
||||||
|
<>
|
||||||
|
<Row1 article={page[0]} noauthor={true} nodate={true} />
|
||||||
|
<Row2 articles={page.slice(1, 3)} isEqual={true} noauthor={true} />
|
||||||
|
<Row1 article={page[3]} noauthor={true} nodate={true} />
|
||||||
|
<Row2 articles={page.slice(4, 6)} isEqual={true} noauthor={true} />
|
||||||
|
<Row1 article={page[6]} noauthor={true} nodate={true} />
|
||||||
|
<Row2 articles={page.slice(7, 9)} isEqual={true} noauthor={true} />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
|
</Show>
|
||||||
|
</Show>
|
||||||
|
</Show>
|
||||||
|
)
|
||||||
return (
|
return (
|
||||||
<div class={styles.authorPage}>
|
<div class={styles.authorPage}>
|
||||||
<div class="wide-container">
|
<div class="wide-container">
|
||||||
|
@ -229,34 +260,8 @@ export const AuthorView = (props: AuthorViewProps) => {
|
||||||
</div>
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
|
|
||||||
<Show when={Array.isArray(props.shouts) && props.shouts.length > 0 && props.shouts[0]}>
|
<AuthorFeed />
|
||||||
<Row1 article={props.shouts?.[0] as Shout} noauthor={true} nodate={true} />
|
|
||||||
|
|
||||||
<Show when={props.shouts && props.shouts.length > 1}>
|
|
||||||
<Switch>
|
|
||||||
<Match when={props.shouts && props.shouts.length === 2}>
|
|
||||||
<Row2 articles={props.shouts as Shout[]} isEqual={true} noauthor={true} nodate={true} />
|
|
||||||
</Match>
|
|
||||||
<Match when={props.shouts && props.shouts.length === 3}>
|
|
||||||
<Row3 articles={props.shouts as Shout[]} noauthor={true} nodate={true} />
|
|
||||||
</Match>
|
|
||||||
<Match when={props.shouts && props.shouts.length > 3}>
|
|
||||||
<For each={pages()}>
|
|
||||||
{(page) => (
|
|
||||||
<>
|
|
||||||
<Row1 article={page[0]} noauthor={true} nodate={true} />
|
|
||||||
<Row2 articles={page.slice(1, 3)} isEqual={true} noauthor={true} />
|
|
||||||
<Row1 article={page[3]} noauthor={true} nodate={true} />
|
|
||||||
<Row2 articles={page.slice(4, 6)} isEqual={true} noauthor={true} />
|
|
||||||
<Row1 article={page[6]} noauthor={true} nodate={true} />
|
|
||||||
<Row2 articles={page.slice(7, 9)} isEqual={true} noauthor={true} />
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</For>
|
|
||||||
</Match>
|
|
||||||
</Switch>
|
|
||||||
</Show>
|
|
||||||
</Show>
|
|
||||||
</Match>
|
</Match>
|
||||||
</Switch>
|
</Switch>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { Author, Reaction, Shout } from '~/graphql/schema/core.gen'
|
||||||
import { byCreated } from '~/lib/sort'
|
import { byCreated } from '~/lib/sort'
|
||||||
import { SortFunction } from '~/types/common'
|
import { SortFunction } from '~/types/common'
|
||||||
import { restoreScrollPosition, saveScrollPosition } from '~/utils/scroll'
|
import { restoreScrollPosition, saveScrollPosition } from '~/utils/scroll'
|
||||||
|
import { Loading } from './Loading'
|
||||||
|
|
||||||
export type LoadMoreItems = Shout[] | Author[] | Reaction[]
|
export type LoadMoreItems = Shout[] | Author[] | Reaction[]
|
||||||
|
|
||||||
|
@ -52,11 +53,11 @@ export const LoadMoreWrapper = (props: LoadMoreProps) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{props.children}
|
{props.children}
|
||||||
<Show when={isLoadMoreButtonVisible() && !props.hidden}>
|
<Show when={isLoading()}><Loading /></Show>
|
||||||
|
<Show when={isLoadMoreButtonVisible() && !props.hidden && !isLoading()}>
|
||||||
<div class="load-more-container">
|
<div class="load-more-container">
|
||||||
<Button
|
<Button
|
||||||
onClick={loadItems}
|
onClick={loadItems}
|
||||||
disabled={isLoading()}
|
|
||||||
value={t('Load more')}
|
value={t('Load more')}
|
||||||
title={`${items().length} ${t('loaded')}`}
|
title={`${items().length} ${t('loaded')}`}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -2,7 +2,7 @@ import type { JSX } from 'solid-js'
|
||||||
|
|
||||||
import { createContext, onCleanup, useContext } from 'solid-js'
|
import { createContext, onCleanup, useContext } from 'solid-js'
|
||||||
import { createStore, reconcile } from 'solid-js/store'
|
import { createStore, reconcile } from 'solid-js/store'
|
||||||
import { loadReactions } from '~/graphql/api/public'
|
import { loadCommentRatings, loadReactions, loadShoutComments, loadShoutRatings } from '~/graphql/api/public'
|
||||||
import createReactionMutation from '~/graphql/mutation/core/reaction-create'
|
import createReactionMutation from '~/graphql/mutation/core/reaction-create'
|
||||||
import destroyReactionMutation from '~/graphql/mutation/core/reaction-destroy'
|
import destroyReactionMutation from '~/graphql/mutation/core/reaction-destroy'
|
||||||
import updateReactionMutation from '~/graphql/mutation/core/reaction-update'
|
import updateReactionMutation from '~/graphql/mutation/core/reaction-update'
|
||||||
|
@ -17,10 +17,16 @@ import { useGraphQL } from './graphql'
|
||||||
import { useLocalize } from './localize'
|
import { useLocalize } from './localize'
|
||||||
import { useSnackbar } from './ui'
|
import { useSnackbar } from './ui'
|
||||||
|
|
||||||
|
export const COMMENTS_PER_PAGE = 50
|
||||||
|
export const RATINGS_PER_PAGE = 100
|
||||||
|
|
||||||
type ReactionsContextType = {
|
type ReactionsContextType = {
|
||||||
reactionEntities: Record<number, Reaction>
|
reactionEntities: Record<number, Reaction>
|
||||||
reactionsByShout: Record<string, Reaction[]>
|
reactionsByShout: Record<string, Reaction[]>
|
||||||
loadReactionsBy: (args: QueryLoad_Reactions_ByArgs) => Promise<Reaction[]>
|
loadReactionsBy: (args: QueryLoad_Reactions_ByArgs) => Promise<Reaction[]>
|
||||||
|
loadShoutComments: (shout: number, limit?: number, offset?: number) => Promise<Reaction[]>
|
||||||
|
loadShoutRatings: (shout: number, limit?: number, offset?: number) => Promise<Reaction[]>
|
||||||
|
loadCommentRatings: (comment: number, limit?: number, offset?: number) => Promise<Reaction[]>
|
||||||
createReaction: (reaction: MutationCreate_ReactionArgs) => Promise<void>
|
createReaction: (reaction: MutationCreate_ReactionArgs) => Promise<void>
|
||||||
updateReaction: (reaction: MutationUpdate_ReactionArgs) => Promise<Reaction>
|
updateReaction: (reaction: MutationUpdate_ReactionArgs) => Promise<Reaction>
|
||||||
deleteReaction: (id: number) => Promise<{ error: string } | null>
|
deleteReaction: (id: number) => Promise<{ error: string } | null>
|
||||||
|
@ -63,6 +69,30 @@ export const ReactionsProvider = (props: { children: JSX.Element }) => {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const loadShoutRatingsAdding = async (shout: number, limit = RATINGS_PER_PAGE, offset = 0): Promise<Reaction[]> => {
|
||||||
|
const fetcher = await loadShoutRatings({ shout, limit, offset })
|
||||||
|
const result = (await fetcher()) || []
|
||||||
|
console.debug('[context.reactions] shout ratings loaded', result)
|
||||||
|
result && addReactions(result)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadCommentRatingsAdding = async (comment: number, limit = RATINGS_PER_PAGE, offset = 0): Promise<Reaction[]> => {
|
||||||
|
const fetcher = await loadCommentRatings({ comment, limit, offset })
|
||||||
|
const result = (await fetcher()) || []
|
||||||
|
console.debug('[context.reactions] shout ratings loaded', result)
|
||||||
|
result && addReactions(result)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadShoutCommentsAdding = async (shout: number, limit = COMMENTS_PER_PAGE, offset = 0): Promise<Reaction[]> => {
|
||||||
|
const fetcher = await loadShoutComments({ shout, limit, offset })
|
||||||
|
const result = (await fetcher()) || []
|
||||||
|
console.debug('[context.reactions] shout comments loaded', result)
|
||||||
|
result && addReactions(result)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
const createReaction = async (input: MutationCreate_ReactionArgs): Promise<void> => {
|
const createReaction = async (input: MutationCreate_ReactionArgs): Promise<void> => {
|
||||||
const resp = await mutation(createReactionMutation, input).toPromise()
|
const resp = await mutation(createReactionMutation, input).toPromise()
|
||||||
const { error, reaction } = resp?.data?.create_reaction || {}
|
const { error, reaction } = resp?.data?.create_reaction || {}
|
||||||
|
@ -122,6 +152,9 @@ export const ReactionsProvider = (props: { children: JSX.Element }) => {
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
loadReactionsBy,
|
loadReactionsBy,
|
||||||
|
loadShoutComments: loadShoutCommentsAdding,
|
||||||
|
loadShoutRatings: loadShoutRatingsAdding,
|
||||||
|
loadCommentRatings: loadCommentRatingsAdding,
|
||||||
createReaction,
|
createReaction,
|
||||||
updateReaction,
|
updateReaction,
|
||||||
deleteReaction,
|
deleteReaction,
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
import { cache } from '@solidjs/router'
|
import { cache } from '@solidjs/router'
|
||||||
import { defaultClient } from '~/context/graphql'
|
import { defaultClient } from '~/context/graphql'
|
||||||
|
import loadShoutCommentsQuery from '~/graphql/query/core/article-comments-load'
|
||||||
import getShoutQuery from '~/graphql/query/core/article-load'
|
import getShoutQuery from '~/graphql/query/core/article-load'
|
||||||
|
import loadShoutRatingsQuery from '~/graphql/query/core/article-ratings-load'
|
||||||
import loadShoutsByQuery from '~/graphql/query/core/articles-load-by'
|
import loadShoutsByQuery from '~/graphql/query/core/articles-load-by'
|
||||||
import loadShoutsSearchQuery from '~/graphql/query/core/articles-load-search'
|
import loadShoutsSearchQuery from '~/graphql/query/core/articles-load-search'
|
||||||
import getAuthorQuery from '~/graphql/query/core/author-by'
|
import getAuthorQuery from '~/graphql/query/core/author-by'
|
||||||
import loadAuthorsAllQuery from '~/graphql/query/core/authors-all'
|
import loadAuthorsAllQuery from '~/graphql/query/core/authors-all'
|
||||||
import loadAuthorsByQuery from '~/graphql/query/core/authors-load-by'
|
import loadAuthorsByQuery from '~/graphql/query/core/authors-load-by'
|
||||||
|
import loadCommentRatingsQuery from '~/graphql/query/core/comment-ratings-load'
|
||||||
import loadReactionsByQuery from '~/graphql/query/core/reactions-load-by'
|
import loadReactionsByQuery from '~/graphql/query/core/reactions-load-by'
|
||||||
import loadFollowersByTopicQuery from '~/graphql/query/core/topic-followers'
|
import loadFollowersByTopicQuery from '~/graphql/query/core/topic-followers'
|
||||||
import loadTopicsQuery from '~/graphql/query/core/topics-all'
|
import loadTopicsQuery from '~/graphql/query/core/topics-all'
|
||||||
|
@ -16,6 +19,7 @@ import {
|
||||||
QueryGet_ShoutArgs,
|
QueryGet_ShoutArgs,
|
||||||
QueryLoad_Authors_ByArgs,
|
QueryLoad_Authors_ByArgs,
|
||||||
QueryLoad_Reactions_ByArgs,
|
QueryLoad_Reactions_ByArgs,
|
||||||
|
QueryLoad_Shout_RatingsArgs,
|
||||||
QueryLoad_Shouts_SearchArgs,
|
QueryLoad_Shouts_SearchArgs,
|
||||||
Reaction,
|
Reaction,
|
||||||
Shout,
|
Shout,
|
||||||
|
@ -57,16 +61,39 @@ export const loadShouts = (options: LoadShoutsOptions) => {
|
||||||
}, `shouts-${filter}-${page}`)
|
}, `shouts-${filter}-${page}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const loadReactions = (options: QueryLoad_Reactions_ByArgs) => {
|
export const loadShoutComments = (options: QueryLoad_Shout_RatingsArgs) => {
|
||||||
if (!options.by) {
|
const page = `${options.offset || 0}-${(options.limit||1) + (options.offset || 0)}`
|
||||||
console.debug(options)
|
return cache(async () => {
|
||||||
throw new Error('[api] wrong loadReactions call')
|
const resp = await defaultClient.query(loadShoutCommentsQuery, options).toPromise()
|
||||||
|
const result = resp?.data?.load_reactions_by
|
||||||
|
if (result) return result as Reaction[]
|
||||||
|
}, `shout-${options.shout}-comments-${page}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const loadShoutRatings = (options: QueryLoad_Shout_RatingsArgs) => {
|
||||||
|
const page = `${options.offset || 0}-${(options.limit||1) + (options.offset || 0)}`
|
||||||
|
return cache(async () => {
|
||||||
|
const resp = await defaultClient.query(loadShoutRatingsQuery, options).toPromise()
|
||||||
|
const result = resp?.data?.load_reactions_by
|
||||||
|
if (result) return result as Reaction[]
|
||||||
|
}, `shout-${options.shout}-ratings-${page}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// biome-ignore lint/suspicious/noExplicitAny: FIXME: wait backend
|
||||||
|
export const loadCommentRatings = (options: any) => {
|
||||||
|
const page = `${options.offset || 0}-${(options.limit||1) + (options.offset || 0)}`
|
||||||
|
return cache(async () => {
|
||||||
|
const resp = await defaultClient.query(loadCommentRatingsQuery, options).toPromise()
|
||||||
|
const result = resp?.data?.load_reactions_by
|
||||||
|
if (result) return result as Reaction[]
|
||||||
|
}, `comment-${options.comment}-ratings-${page}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const loadReactions = (options: QueryLoad_Reactions_ByArgs) => {
|
||||||
const kind = options.by?.comment ? 'comments' : options.by?.rating ? 'votes' : 'reactions'
|
const kind = options.by?.comment ? 'comments' : options.by?.rating ? 'votes' : 'reactions'
|
||||||
const allorone = options.by?.shout ? `shout-${options.by.shout}` : 'all'
|
const allorone = options.by?.shout ? `shout-${options.by.shout}` : 'all'
|
||||||
const page = `${options.offset || 0}-${(options?.limit || 0) + (options.offset || 0)}`
|
const page = `${options.offset || 0}-${(options?.limit || 0) + (options.offset || 0)}`
|
||||||
const filter = new URLSearchParams(options.by as Record<string, string>)
|
const filter = new URLSearchParams(options.by as Record<string, string>)
|
||||||
// console.debug(options)
|
|
||||||
return cache(async () => {
|
return cache(async () => {
|
||||||
const resp = await defaultClient.query(loadReactionsByQuery, options).toPromise()
|
const resp = await defaultClient.query(loadReactionsByQuery, options).toPromise()
|
||||||
const result = resp?.data?.load_reactions_by
|
const result = resp?.data?.load_reactions_by
|
||||||
|
@ -75,7 +102,6 @@ export const loadReactions = (options: QueryLoad_Reactions_ByArgs) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getShout = (options: QueryGet_ShoutArgs) => {
|
export const getShout = (options: QueryGet_ShoutArgs) => {
|
||||||
// console.debug('[lib.api] get shout options', options)
|
|
||||||
return cache(
|
return cache(
|
||||||
async () => {
|
async () => {
|
||||||
const resp = await defaultClient.query(getShoutQuery, { ...options }).toPromise()
|
const resp = await defaultClient.query(getShoutQuery, { ...options }).toPromise()
|
||||||
|
|
29
src/graphql/query/core/article-comments-load.ts
Normal file
29
src/graphql/query/core/article-comments-load.ts
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
import { gql } from '@urql/core'
|
||||||
|
|
||||||
|
export default gql`
|
||||||
|
query LoadReactions($shout: Int!, $limit: Int, $offset: Int) {
|
||||||
|
load_shout_comments(shout: $shout, limit: $limit, offset: $offset) {
|
||||||
|
id
|
||||||
|
kind
|
||||||
|
body
|
||||||
|
reply_to
|
||||||
|
shout {
|
||||||
|
id
|
||||||
|
slug
|
||||||
|
title
|
||||||
|
}
|
||||||
|
created_by {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
slug
|
||||||
|
pic
|
||||||
|
created_at
|
||||||
|
}
|
||||||
|
created_at
|
||||||
|
updated_at
|
||||||
|
stat {
|
||||||
|
rating
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
29
src/graphql/query/core/article-ratings-load.ts
Normal file
29
src/graphql/query/core/article-ratings-load.ts
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
import { gql } from '@urql/core'
|
||||||
|
|
||||||
|
export default gql`
|
||||||
|
query LoadReactions($shout: Int!, $limit: Int, $offset: Int) {
|
||||||
|
load_shout_ratings(shout: $shout, limit: $limit, offset: $offset) {
|
||||||
|
id
|
||||||
|
kind
|
||||||
|
body
|
||||||
|
reply_to
|
||||||
|
shout {
|
||||||
|
id
|
||||||
|
slug
|
||||||
|
title
|
||||||
|
}
|
||||||
|
created_by {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
slug
|
||||||
|
pic
|
||||||
|
created_at
|
||||||
|
}
|
||||||
|
created_at
|
||||||
|
updated_at
|
||||||
|
stat {
|
||||||
|
rating
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
29
src/graphql/query/core/comment-ratings-load.ts
Normal file
29
src/graphql/query/core/comment-ratings-load.ts
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
import { gql } from '@urql/core'
|
||||||
|
|
||||||
|
export default gql`
|
||||||
|
query LoadReactions($comment: Int!, $limit: Int, $offset: Int) {
|
||||||
|
load_comment_ratings(comment: $comment, limit: $limit, offset: $offset) {
|
||||||
|
id
|
||||||
|
kind
|
||||||
|
body
|
||||||
|
reply_to
|
||||||
|
shout {
|
||||||
|
id
|
||||||
|
slug
|
||||||
|
title
|
||||||
|
}
|
||||||
|
created_by {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
slug
|
||||||
|
pic
|
||||||
|
created_at
|
||||||
|
}
|
||||||
|
created_at
|
||||||
|
updated_at
|
||||||
|
stat {
|
||||||
|
rating
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
|
@ -1,5 +1,5 @@
|
||||||
import { RouteSectionProps } from '@solidjs/router'
|
import { RouteSectionProps, createAsync } from '@solidjs/router'
|
||||||
import { ErrorBoundary, createEffect, createMemo, createSignal, on } from 'solid-js'
|
import { ErrorBoundary, createEffect, createMemo } from 'solid-js'
|
||||||
import { AuthorView } from '~/components/Views/Author'
|
import { AuthorView } from '~/components/Views/Author'
|
||||||
import { FourOuFourView } from '~/components/Views/FourOuFour'
|
import { FourOuFourView } from '~/components/Views/FourOuFour'
|
||||||
import { LoadMoreItems, LoadMoreWrapper } from '~/components/_shared/LoadMoreWrapper'
|
import { LoadMoreItems, LoadMoreWrapper } from '~/components/_shared/LoadMoreWrapper'
|
||||||
|
@ -33,6 +33,7 @@ const fetchAllTopics = async () => {
|
||||||
const fetchAuthor = async (slug: string) => {
|
const fetchAuthor = async (slug: string) => {
|
||||||
const authorFetcher = loadAuthors({ by: { slug }, limit: 1, offset: 0 } as QueryLoad_Authors_ByArgs)
|
const authorFetcher = loadAuthors({ by: { slug }, limit: 1, offset: 0 } as QueryLoad_Authors_ByArgs)
|
||||||
const aaa = await authorFetcher()
|
const aaa = await authorFetcher()
|
||||||
|
console.debug(aaa)
|
||||||
return aaa?.[0]
|
return aaa?.[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,11 +51,17 @@ export const route = {
|
||||||
export type AuthorPageProps = { articles?: Shout[]; author?: Author; topics?: Topic[] }
|
export type AuthorPageProps = { articles?: Shout[]; author?: Author; topics?: Topic[] }
|
||||||
|
|
||||||
export default function AuthorPage(props: RouteSectionProps<AuthorPageProps>) {
|
export default function AuthorPage(props: RouteSectionProps<AuthorPageProps>) {
|
||||||
const { addAuthor, authorsEntities } = useAuthors()
|
const { authorsEntities } = useAuthors()
|
||||||
const [author, setAuthor] = createSignal<Author | undefined>(undefined)
|
const { addFeed, feedByAuthor } = useFeed()
|
||||||
|
|
||||||
const { t } = useLocalize()
|
const { t } = useLocalize()
|
||||||
|
const author = createAsync(async() => props.data.author || authorsEntities()[props.params.slug] || await fetchAuthor(props.params.slug))
|
||||||
|
const shoutsByAuthor = createMemo(() => feedByAuthor()[props.params.slug])
|
||||||
const title = createMemo(() => `${author()?.name || ''}`)
|
const title = createMemo(() => `${author()?.name || ''}`)
|
||||||
|
const cover = createMemo(() =>
|
||||||
|
author()?.pic
|
||||||
|
? getImageUrl(author()?.pic || '', { width: 1200 })
|
||||||
|
: getImageUrl('production/image/logo_image.png')
|
||||||
|
)
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
if (author()) {
|
if (author()) {
|
||||||
|
@ -67,32 +74,8 @@ export default function AuthorPage(props: RouteSectionProps<AuthorPageProps>) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const cover = createMemo(() =>
|
|
||||||
author()?.pic
|
|
||||||
? getImageUrl(author()?.pic || '', { width: 1200 })
|
|
||||||
: getImageUrl('production/image/logo_image.png')
|
|
||||||
)
|
|
||||||
|
|
||||||
// author shouts
|
// author shouts
|
||||||
const { addFeed, feedByAuthor } = useFeed()
|
|
||||||
const shoutsByAuthor = createMemo(() => feedByAuthor()[props.params.slug])
|
|
||||||
|
|
||||||
createEffect(
|
|
||||||
on(
|
|
||||||
[() => props.params.slug || '', author],
|
|
||||||
async ([slug, profile]) => {
|
|
||||||
if (!profile) {
|
|
||||||
const loadedAuthor = authorsEntities()[slug] || (await fetchAuthor(slug))
|
|
||||||
if (loadedAuthor) {
|
|
||||||
addAuthor(loadedAuthor)
|
|
||||||
setAuthor(loadedAuthor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ defer: true }
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
const loadAuthorShoutsMore = async (offset: number) => {
|
const loadAuthorShoutsMore = async (offset: number) => {
|
||||||
const loadedShouts = await fetchAuthorShouts(props.params.slug, offset)
|
const loadedShouts = await fetchAuthorShouts(props.params.slug, offset)
|
||||||
loadedShouts && addFeed(loadedShouts)
|
loadedShouts && addFeed(loadedShouts)
|
||||||
|
|
|
@ -125,7 +125,7 @@ export default (props: RouteSectionProps<{ shouts: Shout[]; topics: Topic[] }>)
|
||||||
key="feed"
|
key="feed"
|
||||||
desc="Independent media project about culture, science, art and society with horizontal editing"
|
desc="Independent media project about culture, science, art and society with horizontal editing"
|
||||||
>
|
>
|
||||||
<LoadMoreWrapper loadFunction={loadMoreFeed} pageSize={AUTHORS_PER_PAGE}>
|
<LoadMoreWrapper loadFunction={loadMoreFeed} pageSize={AUTHORS_PER_PAGE} hidden={!feed()}>
|
||||||
<ReactionsProvider>
|
<ReactionsProvider>
|
||||||
<Feed shouts={feed() || (shouts() as Shout[])} order={order() as FeedProps['order']} />
|
<Feed shouts={feed() || (shouts() as Shout[])} order={order() as FeedProps['order']} />
|
||||||
</ReactionsProvider>
|
</ReactionsProvider>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user