article page. & comments fix
This commit is contained in:
parent
2a70e3ebc5
commit
e332a8a674
|
@ -1,11 +1,10 @@
|
||||||
import { For, Show } from 'solid-js'
|
import { For, Show, createMemo, createSignal, onMount } from 'solid-js'
|
||||||
import { useSession } from '../../context/session'
|
import { useSession } from '../../context/session'
|
||||||
import Comment from './Comment'
|
import Comment from './Comment'
|
||||||
import { t } from '../../utils/intl'
|
import { t } from '../../utils/intl'
|
||||||
import { showModal } from '../../stores/ui'
|
import { showModal } from '../../stores/ui'
|
||||||
import styles from '../../styles/Article.module.scss'
|
import styles from '../../styles/Article.module.scss'
|
||||||
import { useReactionsStore } from '../../stores/zine/reactions'
|
import { useReactionsStore } from '../../stores/zine/reactions'
|
||||||
import { createMemo, createSignal, onMount } from 'solid-js'
|
|
||||||
import type { Reaction } from '../../graphql/types.gen'
|
import type { Reaction } from '../../graphql/types.gen'
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
import { byCreated, byStat } from '../../utils/sortby'
|
import { byCreated, byStat } from '../../utils/sortby'
|
||||||
|
@ -14,17 +13,17 @@ import { Loading } from '../Loading'
|
||||||
const ARTICLE_COMMENTS_PAGE_SIZE = 50
|
const ARTICLE_COMMENTS_PAGE_SIZE = 50
|
||||||
const MAX_COMMENT_LEVEL = 6
|
const MAX_COMMENT_LEVEL = 6
|
||||||
|
|
||||||
export const CommentsTree = (props: { shout: string; reactions?: Reaction[] }) => {
|
export const CommentsTree = (props: { shoutSlug: string }) => {
|
||||||
const [getCommentsPage, setCommentsPage] = createSignal(0)
|
const [getCommentsPage, setCommentsPage] = createSignal(0)
|
||||||
const [commentsOrder, setCommentsOrder] = createSignal<'rating' | 'createdAt'>('createdAt')
|
const [commentsOrder, setCommentsOrder] = createSignal<'rating' | 'createdAt'>('createdAt')
|
||||||
const [isCommentsLoading, setIsCommentsLoading] = createSignal(false)
|
const [isCommentsLoading, setIsCommentsLoading] = createSignal(false)
|
||||||
const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false)
|
const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false)
|
||||||
const { session } = useSession()
|
const { session } = useSession()
|
||||||
const { sortedReactions, loadReactionsBy } = useReactionsStore({ reactions: props.reactions })
|
const { sortedReactions, loadReactionsBy } = useReactionsStore()
|
||||||
const reactions = createMemo<Reaction[]>(() =>
|
const reactions = createMemo<Reaction[]>(() =>
|
||||||
sortedReactions()
|
sortedReactions()
|
||||||
.sort(commentsOrder() === 'rating' ? byStat('rating') : byCreated)
|
.sort(commentsOrder() === 'rating' ? byStat('rating') : byCreated)
|
||||||
.filter((r) => r.shout.slug === props.shout)
|
.filter((r) => r.shout.slug === props.shoutSlug)
|
||||||
)
|
)
|
||||||
|
|
||||||
const loadMore = async () => {
|
const loadMore = async () => {
|
||||||
|
@ -33,7 +32,7 @@ export const CommentsTree = (props: { shout: string; reactions?: Reaction[] }) =
|
||||||
setIsCommentsLoading(true)
|
setIsCommentsLoading(true)
|
||||||
|
|
||||||
const { hasMore } = await loadReactionsBy({
|
const { hasMore } = await loadReactionsBy({
|
||||||
by: { shout: props.shout, comment: true },
|
by: { shout: props.shoutSlug, comment: true },
|
||||||
limit: ARTICLE_COMMENTS_PAGE_SIZE,
|
limit: ARTICLE_COMMENTS_PAGE_SIZE,
|
||||||
offset: page * ARTICLE_COMMENTS_PAGE_SIZE
|
offset: page * ARTICLE_COMMENTS_PAGE_SIZE
|
||||||
})
|
})
|
||||||
|
|
|
@ -222,7 +222,7 @@ export const FullArticle = (props: ArticleProps) => {
|
||||||
)}
|
)}
|
||||||
</For>
|
</For>
|
||||||
</div>
|
</div>
|
||||||
<CommentsTree shout={props.article?.slug} />
|
<CommentsTree shoutSlug={props.article?.slug} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
|
@ -32,6 +32,7 @@ interface AuthorCardProps {
|
||||||
export const AuthorCard = (props: AuthorCardProps) => {
|
export const AuthorCard = (props: AuthorCardProps) => {
|
||||||
const {
|
const {
|
||||||
session,
|
session,
|
||||||
|
isSessionLoaded,
|
||||||
actions: { loadSession }
|
actions: { loadSession }
|
||||||
} = useSession()
|
} = useSession()
|
||||||
|
|
||||||
|
@ -100,7 +101,7 @@ export const AuthorCard = (props: AuthorCardProps) => {
|
||||||
</Show>
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
<ShowOnlyOnClient>
|
<ShowOnlyOnClient>
|
||||||
<Show when={session.state !== 'pending'}>
|
<Show when={isSessionLoaded()}>
|
||||||
<Show when={canFollow()}>
|
<Show when={canFollow()}>
|
||||||
<div class={styles.authorSubscribe}>
|
<div class={styles.authorSubscribe}>
|
||||||
<Show
|
<Show
|
||||||
|
|
|
@ -21,7 +21,7 @@ export const HeaderAuth = (props: HeaderAuthProps) => {
|
||||||
const [visibleWarnings, setVisibleWarnings] = createSignal(false)
|
const [visibleWarnings, setVisibleWarnings] = createSignal(false)
|
||||||
const { warnings } = useWarningsStore()
|
const { warnings } = useWarningsStore()
|
||||||
|
|
||||||
const { session, isAuthenticated } = useSession()
|
const { session, isSessionLoaded, isAuthenticated } = useSession()
|
||||||
|
|
||||||
const toggleWarnings = () => setVisibleWarnings(!visibleWarnings())
|
const toggleWarnings = () => setVisibleWarnings(!visibleWarnings())
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ export const HeaderAuth = (props: HeaderAuthProps) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ShowOnlyOnClient>
|
<ShowOnlyOnClient>
|
||||||
<Show when={session.state !== 'pending'}>
|
<Show when={isSessionLoaded()}>
|
||||||
<div class={styles.usernav}>
|
<div class={styles.usernav}>
|
||||||
<div class={clsx(styles.userControl, styles.userControl, 'col')}>
|
<div class={clsx(styles.userControl, styles.userControl, 'col')}>
|
||||||
<div class={clsx(styles.userControlItem, styles.userControlItemVerbose)}>
|
<div class={clsx(styles.userControlItem, styles.userControlItemVerbose)}>
|
||||||
|
|
|
@ -28,6 +28,7 @@ interface TopicProps {
|
||||||
export const TopicCard = (props: TopicProps) => {
|
export const TopicCard = (props: TopicProps) => {
|
||||||
const {
|
const {
|
||||||
session,
|
session,
|
||||||
|
isSessionLoaded,
|
||||||
actions: { loadSession }
|
actions: { loadSession }
|
||||||
} = useSession()
|
} = useSession()
|
||||||
|
|
||||||
|
@ -89,7 +90,7 @@ export const TopicCard = (props: TopicProps) => {
|
||||||
classList={{ 'col-md-3': !props.compact && !props.subscribeButtonBottom }}
|
classList={{ 'col-md-3': !props.compact && !props.subscribeButtonBottom }}
|
||||||
>
|
>
|
||||||
<ShowOnlyOnClient>
|
<ShowOnlyOnClient>
|
||||||
<Show when={session.state !== 'pending'}>
|
<Show when={isSessionLoaded()}>
|
||||||
<button
|
<button
|
||||||
onClick={() => subscribe(!subscribed())}
|
onClick={() => subscribe(!subscribed())}
|
||||||
class="button--light button--subscribe-topic"
|
class="button--light button--subscribe-topic"
|
||||||
|
|
|
@ -27,7 +27,7 @@ export const FEED_PAGE_SIZE = 20
|
||||||
export const FeedView = () => {
|
export const FeedView = () => {
|
||||||
// state
|
// state
|
||||||
const { sortedArticles } = useArticlesStore()
|
const { sortedArticles } = useArticlesStore()
|
||||||
const { sortedReactions: topComments, loadReactionsBy } = useReactionsStore({})
|
const { sortedReactions: topComments, loadReactionsBy } = useReactionsStore()
|
||||||
const { sortedAuthors } = useAuthorsStore()
|
const { sortedAuthors } = useAuthorsStore()
|
||||||
const { topTopics } = useTopicsStore()
|
const { topTopics } = useTopicsStore()
|
||||||
const { topAuthors } = useTopAuthorsStore()
|
const { topAuthors } = useTopAuthorsStore()
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
import type { Accessor, JSX, Resource } from 'solid-js'
|
import type { Accessor, JSX, Resource } from 'solid-js'
|
||||||
import { createContext, createMemo, createResource, onMount, useContext } from 'solid-js'
|
import { createContext, createMemo, createResource, createSignal, onMount, useContext } from 'solid-js'
|
||||||
import type { AuthResult } from '../graphql/types.gen'
|
import type { AuthResult } from '../graphql/types.gen'
|
||||||
import { apiClient } from '../utils/apiClient'
|
import { apiClient } from '../utils/apiClient'
|
||||||
import { resetToken, setToken } from '../graphql/privateGraphQLClient'
|
import { resetToken, setToken } from '../graphql/privateGraphQLClient'
|
||||||
|
|
||||||
type SessionContextType = {
|
type SessionContextType = {
|
||||||
session: Resource<AuthResult>
|
session: Resource<AuthResult>
|
||||||
|
isSessionLoaded: Accessor<boolean>
|
||||||
userSlug: Accessor<string>
|
userSlug: Accessor<string>
|
||||||
isAuthenticated: Accessor<boolean>
|
isAuthenticated: Accessor<boolean>
|
||||||
actions: {
|
actions: {
|
||||||
|
@ -18,27 +19,33 @@ type SessionContextType = {
|
||||||
|
|
||||||
const SessionContext = createContext<SessionContextType>()
|
const SessionContext = createContext<SessionContextType>()
|
||||||
|
|
||||||
const getSession = async (): Promise<AuthResult> => {
|
|
||||||
try {
|
|
||||||
const authResult = await apiClient.getSession()
|
|
||||||
if (!authResult) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
setToken(authResult.token)
|
|
||||||
return authResult
|
|
||||||
} catch (error) {
|
|
||||||
console.error('getSession error:', error)
|
|
||||||
resetToken()
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useSession() {
|
export function useSession() {
|
||||||
return useContext(SessionContext)
|
return useContext(SessionContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SessionProvider = (props: { children: JSX.Element }) => {
|
export const SessionProvider = (props: { children: JSX.Element }) => {
|
||||||
const [session, { refetch: loadSession, mutate }] = createResource<AuthResult>(getSession)
|
const [isSessionLoaded, setIsSessionLoaded] = createSignal(false)
|
||||||
|
|
||||||
|
const getSession = async (): Promise<AuthResult> => {
|
||||||
|
try {
|
||||||
|
const authResult = await apiClient.getSession()
|
||||||
|
if (!authResult) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
setToken(authResult.token)
|
||||||
|
setIsSessionLoaded(true)
|
||||||
|
return authResult
|
||||||
|
} catch (error) {
|
||||||
|
console.error('getSession error:', error)
|
||||||
|
resetToken()
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const [session, { refetch: loadSession, mutate }] = createResource<AuthResult>(getSession, {
|
||||||
|
ssrLoadFrom: 'initial',
|
||||||
|
initialValue: null
|
||||||
|
})
|
||||||
|
|
||||||
const userSlug = createMemo(() => session()?.user?.slug)
|
const userSlug = createMemo(() => session()?.user?.slug)
|
||||||
|
|
||||||
|
@ -71,7 +78,7 @@ export const SessionProvider = (props: { children: JSX.Element }) => {
|
||||||
confirmEmail
|
confirmEmail
|
||||||
}
|
}
|
||||||
|
|
||||||
const value: SessionContextType = { session, userSlug, isAuthenticated, actions }
|
const value: SessionContextType = { session, isSessionLoaded, userSlug, isAuthenticated, actions }
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
loadSession()
|
loadSession()
|
||||||
|
|
|
@ -22,8 +22,8 @@ export type AuthResult = {
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Author = {
|
export type Author = {
|
||||||
bio?: Maybe<Scalars['String']>
|
|
||||||
about?: Maybe<Scalars['String']>
|
about?: Maybe<Scalars['String']>
|
||||||
|
bio?: Maybe<Scalars['String']>
|
||||||
caption?: Maybe<Scalars['String']>
|
caption?: Maybe<Scalars['String']>
|
||||||
id: Scalars['Int']
|
id: Scalars['Int']
|
||||||
lastSeen?: Maybe<Scalars['DateTime']>
|
lastSeen?: Maybe<Scalars['DateTime']>
|
||||||
|
@ -334,8 +334,6 @@ export type Permission = {
|
||||||
export type ProfileInput = {
|
export type ProfileInput = {
|
||||||
about?: InputMaybe<Scalars['String']>
|
about?: InputMaybe<Scalars['String']>
|
||||||
bio?: InputMaybe<Scalars['String']>
|
bio?: InputMaybe<Scalars['String']>
|
||||||
slug?: InputMaybe<Scalars['String']>
|
|
||||||
about?: InputMaybe<Scalars['String']>
|
|
||||||
links?: InputMaybe<Array<InputMaybe<Scalars['String']>>>
|
links?: InputMaybe<Array<InputMaybe<Scalars['String']>>>
|
||||||
name?: InputMaybe<Scalars['String']>
|
name?: InputMaybe<Scalars['String']>
|
||||||
slug?: InputMaybe<Scalars['String']>
|
slug?: InputMaybe<Scalars['String']>
|
||||||
|
|
|
@ -37,11 +37,7 @@ export const deleteReaction = async (reactionId: number) => {
|
||||||
console.debug(resp)
|
console.debug(resp)
|
||||||
return resp
|
return resp
|
||||||
}
|
}
|
||||||
export const useReactionsStore = (initialState: { reactions?: Reaction[] }) => {
|
export const useReactionsStore = () => {
|
||||||
if (initialState.reactions) {
|
|
||||||
setSortedReactions([...initialState.reactions])
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
reactionsByShout,
|
reactionsByShout,
|
||||||
sortedReactions,
|
sortedReactions,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user