signIn/getSession optimizaiton frontend (#272)
Co-authored-by: Igor Lobanov <igor.lobanov@onetwotrip.com>
This commit is contained in:
parent
85e8533931
commit
891d29ff6a
|
@ -17,13 +17,14 @@ export const AuthorBadge = (props: Props) => {
|
|||
const [isSubscribing, setIsSubscribing] = createSignal(false)
|
||||
const {
|
||||
session,
|
||||
actions: { loadSession, requireAuthentication }
|
||||
subscriptions,
|
||||
actions: { loadSubscriptions, requireAuthentication }
|
||||
} = useSession()
|
||||
|
||||
const { t, formatDate } = useLocalize()
|
||||
const subscribed = createMemo<boolean>(() => {
|
||||
return session()?.news?.authors?.some((u) => u === props.author.slug) || false
|
||||
})
|
||||
const subscribed = createMemo(() =>
|
||||
subscriptions().authors.some((author) => author.slug === props.author.slug)
|
||||
)
|
||||
|
||||
const subscribe = async (really = true) => {
|
||||
setIsSubscribing(true)
|
||||
|
@ -32,7 +33,7 @@ export const AuthorBadge = (props: Props) => {
|
|||
? follow({ what: FollowingEntity.Author, slug: props.author.slug })
|
||||
: unfollow({ what: FollowingEntity.Author, slug: props.author.slug }))
|
||||
|
||||
await loadSession()
|
||||
await loadSubscriptions()
|
||||
setIsSubscribing(false)
|
||||
}
|
||||
const handleSubscribe = (really: boolean) => {
|
||||
|
|
|
@ -50,8 +50,9 @@ export const AuthorCard = (props: Props) => {
|
|||
const { t, lang } = useLocalize()
|
||||
const {
|
||||
session,
|
||||
subscriptions,
|
||||
isSessionLoaded,
|
||||
actions: { loadSession, requireAuthentication }
|
||||
actions: { loadSubscriptions, requireAuthentication }
|
||||
} = useSession()
|
||||
|
||||
const [isSubscribing, setIsSubscribing] = createSignal(false)
|
||||
|
@ -59,9 +60,9 @@ export const AuthorCard = (props: Props) => {
|
|||
const [subscriptionFilter, setSubscriptionFilter] = createSignal<SubscriptionFilter>('all')
|
||||
const [userpicUrl, setUserpicUrl] = createSignal<string>()
|
||||
|
||||
const subscribed = createMemo<boolean>(() => {
|
||||
return session()?.news?.authors?.some((u) => u === props.author.slug) || false
|
||||
})
|
||||
const subscribed = createMemo<boolean>(() =>
|
||||
subscriptions().authors.some((author) => author.slug === props.author.slug)
|
||||
)
|
||||
|
||||
const subscribe = async (really = true) => {
|
||||
setIsSubscribing(true)
|
||||
|
@ -70,7 +71,7 @@ export const AuthorCard = (props: Props) => {
|
|||
? follow({ what: FollowingEntity.Author, slug: props.author.slug })
|
||||
: unfollow({ what: FollowingEntity.Author, slug: props.author.slug }))
|
||||
|
||||
await loadSession()
|
||||
await loadSubscriptions()
|
||||
setIsSubscribing(false)
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ type FeedSidebarProps = {
|
|||
export const Sidebar = (props: FeedSidebarProps) => {
|
||||
const { t } = useLocalize()
|
||||
const { seen } = useSeenStore()
|
||||
const { session } = useSession()
|
||||
const { subscriptions } = useSession()
|
||||
const { page } = useRouter()
|
||||
const { authorEntities } = useAuthorsStore({ authors: props.authors })
|
||||
const { articlesByTopic } = useArticlesStore()
|
||||
|
@ -118,7 +118,7 @@ export const Sidebar = (props: FeedSidebarProps) => {
|
|||
</li>
|
||||
</ul>
|
||||
|
||||
<Show when={session()?.news?.authors || session()?.news?.topics}>
|
||||
<Show when={subscriptions().authors.length > 0 || subscriptions().topics.length > 0}>
|
||||
<h4
|
||||
classList={{ [styles.opened]: isSubscriptionsVisible() }}
|
||||
onClick={() => {
|
||||
|
@ -129,39 +129,31 @@ export const Sidebar = (props: FeedSidebarProps) => {
|
|||
</h4>
|
||||
|
||||
<ul class={clsx(styles.subscriptions, { [styles.hidden]: !isSubscriptionsVisible() })}>
|
||||
<For each={session()?.news?.authors}>
|
||||
{(authorSlug: string) => (
|
||||
<For each={subscriptions().authors}>
|
||||
{(author) => (
|
||||
<li>
|
||||
<a
|
||||
href={`/author/${authorSlug}`}
|
||||
classList={{ [styles.unread]: checkAuthorIsSeen(authorSlug) }}
|
||||
href={`/author/${author.slug}`}
|
||||
classList={{ [styles.unread]: checkAuthorIsSeen(author.slug) }}
|
||||
>
|
||||
<div class={styles.sidebarItemName}>
|
||||
<Show when={authorEntities()[authorSlug]}>
|
||||
<Userpic
|
||||
name={authorEntities()[authorSlug].name}
|
||||
userpic={authorEntities()[authorSlug].userpic}
|
||||
/>
|
||||
</Show>
|
||||
<Show when={!authorEntities()[authorSlug]}>
|
||||
<Icon name="hash" class={styles.icon} />
|
||||
</Show>
|
||||
{authorEntities()[authorSlug]?.name}
|
||||
<Userpic name={author.name} userpic={author.userpic} />
|
||||
{author.name}
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
)}
|
||||
</For>
|
||||
<For each={session()?.news?.topics}>
|
||||
{(topicSlug: string) => (
|
||||
<For each={subscriptions().topics}>
|
||||
{(topic) => (
|
||||
<li>
|
||||
<a
|
||||
href={`/topic/${topicSlug}`}
|
||||
classList={{ [styles.unread]: checkTopicIsSeen(topicSlug) }}
|
||||
href={`/topic/${topic.slug}`}
|
||||
classList={{ [styles.unread]: checkTopicIsSeen(topic.slug) }}
|
||||
>
|
||||
<div class={styles.sidebarItemName}>
|
||||
<Icon name="hash" class={styles.icon} />
|
||||
{topicEntities()[topicSlug]?.title ?? topicSlug}
|
||||
{topic.title}
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
|
|
|
@ -186,12 +186,8 @@ export const HeaderAuth = (props: Props) => {
|
|||
<a href="/inbox">
|
||||
{/*FIXME: replace with route*/}
|
||||
<div classList={{ entered: page().path === '/inbox' }}>
|
||||
<Icon name="inbox-white" counter={session()?.news?.unread || 0} class={styles.icon} />
|
||||
<Icon
|
||||
name="inbox-white-hover"
|
||||
counter={session()?.news?.unread || 0}
|
||||
class={clsx(styles.icon, styles.iconHover)}
|
||||
/>
|
||||
<Icon name="inbox-white" class={styles.icon} />
|
||||
<Icon name="inbox-white-hover" class={clsx(styles.icon, styles.iconHover)} />
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
|
|
@ -34,19 +34,15 @@ interface TopicProps {
|
|||
export const TopicCard = (props: TopicProps) => {
|
||||
const { t } = useLocalize()
|
||||
const {
|
||||
session,
|
||||
subscriptions,
|
||||
isSessionLoaded,
|
||||
actions: { loadSession, requireAuthentication }
|
||||
actions: { loadSubscriptions, requireAuthentication }
|
||||
} = useSession()
|
||||
|
||||
const [isSubscribing, setIsSubscribing] = createSignal(false)
|
||||
|
||||
const subscribed = createMemo(() => {
|
||||
if (!session()?.user?.slug || !session()?.news?.topics) {
|
||||
return false
|
||||
}
|
||||
|
||||
return session()?.news.topics.includes(props.topic.slug)
|
||||
return subscriptions().topics.some((topic) => topic.slug === props.topic.slug)
|
||||
})
|
||||
|
||||
const subscribe = async (really = true) => {
|
||||
|
@ -56,7 +52,7 @@ export const TopicCard = (props: TopicProps) => {
|
|||
? follow({ what: FollowingEntity.Topic, slug: props.topic.slug })
|
||||
: unfollow({ what: FollowingEntity.Topic, slug: props.topic.slug }))
|
||||
|
||||
await loadSession()
|
||||
await loadSubscriptions()
|
||||
setIsSubscribing(false)
|
||||
}
|
||||
|
||||
|
|
|
@ -14,11 +14,15 @@ type Props = {
|
|||
|
||||
export const FullTopic = (props: Props) => {
|
||||
const {
|
||||
session,
|
||||
subscriptions,
|
||||
actions: { requireAuthentication }
|
||||
} = useSession()
|
||||
|
||||
const { t } = useLocalize()
|
||||
const subscribed = createMemo(() => session()?.news?.topics?.includes(props.topic?.slug))
|
||||
|
||||
const subscribed = createMemo(() =>
|
||||
subscriptions().topics.some((topic) => topic.slug === props.topic?.slug)
|
||||
)
|
||||
|
||||
const handleSubscribe = (isFollowed: boolean) => {
|
||||
requireAuthentication(() => {
|
||||
|
|
|
@ -19,17 +19,13 @@ export const TopicBadge = (props: Props) => {
|
|||
const { t } = useLocalize()
|
||||
const {
|
||||
isAuthenticated,
|
||||
session,
|
||||
actions: { loadSession }
|
||||
subscriptions,
|
||||
actions: { loadSubscriptions }
|
||||
} = useSession()
|
||||
|
||||
const subscribed = createMemo(() => {
|
||||
if (!session()?.user?.slug || !session()?.news?.topics) {
|
||||
return false
|
||||
}
|
||||
|
||||
return session()?.news.topics.includes(props.topic.slug)
|
||||
})
|
||||
const subscribed = createMemo(() =>
|
||||
subscriptions().topics.some((topic) => topic.slug === props.topic.slug)
|
||||
)
|
||||
|
||||
const subscribe = async (really = true) => {
|
||||
setIsSubscribing(true)
|
||||
|
@ -38,7 +34,7 @@ export const TopicBadge = (props: Props) => {
|
|||
? follow({ what: FollowingEntity.Topic, slug: props.topic.slug })
|
||||
: unfollow({ what: FollowingEntity.Topic, slug: props.topic.slug }))
|
||||
|
||||
await loadSession()
|
||||
await loadSubscriptions()
|
||||
setIsSubscribing(false)
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ export const AllAuthorsView = (props: AllAuthorsViewProps) => {
|
|||
|
||||
const [searchQuery, setSearchQuery] = createSignal('')
|
||||
|
||||
const { session } = useSession()
|
||||
const { session, subscriptions } = useSession()
|
||||
|
||||
onMount(() => {
|
||||
if (!searchParams().by) {
|
||||
|
@ -72,7 +72,8 @@ export const AllAuthorsView = (props: AllAuthorsViewProps) => {
|
|||
return keys
|
||||
})
|
||||
|
||||
const subscribed = (s) => Boolean(session()?.news?.authors && session()?.news?.authors?.includes(s || ''))
|
||||
const subscribed = (authorSlug: string) =>
|
||||
subscriptions().authors.some((author) => author.slug === authorSlug)
|
||||
|
||||
const filteredAuthors = createMemo(() => {
|
||||
return dummyFilter(sortedAuthors(), searchQuery(), lang())
|
||||
|
|
|
@ -34,7 +34,7 @@ export const AllTopicsView = (props: AllTopicsViewProps) => {
|
|||
sortBy: searchParams().by || 'shouts'
|
||||
})
|
||||
|
||||
const { session } = useSession()
|
||||
const { session, subscriptions } = useSession()
|
||||
|
||||
onMount(() => {
|
||||
if (!searchParams().by) {
|
||||
|
@ -68,7 +68,7 @@ export const AllTopicsView = (props: AllTopicsViewProps) => {
|
|||
return keys
|
||||
})
|
||||
|
||||
const subscribed = (s) => Boolean(session()?.news?.topics && session()?.news?.topics?.includes(s || ''))
|
||||
const subscribed = (topicSlug: string) => subscriptions().topics.some((topic) => topic.slug === topicSlug)
|
||||
|
||||
const showMore = () => setLimit((oldLimit) => oldLimit + PAGE_SIZE)
|
||||
const [searchQuery, setSearchQuery] = createSignal('')
|
||||
|
|
|
@ -8,7 +8,7 @@ import {
|
|||
onMount,
|
||||
useContext
|
||||
} from 'solid-js'
|
||||
import type { AuthResult, User } from '../graphql/types.gen'
|
||||
import type { AuthResult, MySubscriptionsQueryResult, User } from '../graphql/types.gen'
|
||||
import { apiClient } from '../utils/apiClient'
|
||||
import { resetToken, setToken } from '../graphql/privateGraphQLClient'
|
||||
import { useSnackbar } from './snackbar'
|
||||
|
@ -19,10 +19,12 @@ import type { AuthModalSource } from '../components/Nav/AuthModal/types'
|
|||
type SessionContextType = {
|
||||
session: Resource<AuthResult>
|
||||
isSessionLoaded: Accessor<boolean>
|
||||
subscriptions: Accessor<MySubscriptionsQueryResult>
|
||||
user: Accessor<User>
|
||||
isAuthenticated: Accessor<boolean>
|
||||
actions: {
|
||||
loadSession: () => AuthResult | Promise<AuthResult>
|
||||
loadSubscriptions: () => Promise<void>
|
||||
requireAuthentication: (
|
||||
callback: (() => Promise<void>) | (() => void),
|
||||
modalSource: AuthModalSource
|
||||
|
@ -41,6 +43,10 @@ export function useSession() {
|
|||
|
||||
export const SessionProvider = (props: { children: JSX.Element }) => {
|
||||
const [isSessionLoaded, setIsSessionLoaded] = createSignal(false)
|
||||
const [subscriptions, setSubscriptions] = createSignal<MySubscriptionsQueryResult>({
|
||||
topics: [],
|
||||
authors: []
|
||||
})
|
||||
const { t } = useLocalize()
|
||||
const {
|
||||
actions: { showSnackbar }
|
||||
|
@ -53,6 +59,7 @@ export const SessionProvider = (props: { children: JSX.Element }) => {
|
|||
return null
|
||||
}
|
||||
setToken(authResult.token)
|
||||
loadSubscriptions()
|
||||
return authResult
|
||||
} catch (error) {
|
||||
console.error('getSession error:', error)
|
||||
|
@ -63,6 +70,11 @@ export const SessionProvider = (props: { children: JSX.Element }) => {
|
|||
}
|
||||
}
|
||||
|
||||
const loadSubscriptions = async (): Promise<void> => {
|
||||
const result = await apiClient.getMySubscriptions()
|
||||
setSubscriptions(result)
|
||||
}
|
||||
|
||||
const [session, { refetch: loadSession, mutate }] = createResource<AuthResult>(getSession, {
|
||||
ssrLoadFrom: 'initial',
|
||||
initialValue: null
|
||||
|
@ -76,7 +88,8 @@ export const SessionProvider = (props: { children: JSX.Element }) => {
|
|||
const authResult = await apiClient.authLogin({ email, password })
|
||||
setToken(authResult.token)
|
||||
mutate(authResult)
|
||||
console.debug('signed in')
|
||||
loadSubscriptions()
|
||||
// console.debug('signed in')
|
||||
}
|
||||
|
||||
const [isAuthWithCallback, setIsAuthWithCallback] = createSignal(null)
|
||||
|
@ -119,10 +132,18 @@ export const SessionProvider = (props: { children: JSX.Element }) => {
|
|||
requireAuthentication,
|
||||
signIn,
|
||||
signOut,
|
||||
confirmEmail
|
||||
confirmEmail,
|
||||
loadSubscriptions
|
||||
}
|
||||
|
||||
const value: SessionContextType = { session, isSessionLoaded, user, isAuthenticated, actions }
|
||||
const value: SessionContextType = {
|
||||
session,
|
||||
subscriptions,
|
||||
isSessionLoaded,
|
||||
user,
|
||||
isAuthenticated,
|
||||
actions
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
loadSession()
|
||||
|
|
|
@ -14,13 +14,6 @@ export default gql`
|
|||
userpic
|
||||
links
|
||||
}
|
||||
news {
|
||||
unread
|
||||
topics
|
||||
authors
|
||||
reactions
|
||||
communities
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
|
|
@ -13,13 +13,6 @@ export default gql`
|
|||
userpic
|
||||
links
|
||||
}
|
||||
news {
|
||||
unread
|
||||
topics
|
||||
authors
|
||||
reactions
|
||||
# communities
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
|
21
src/graphql/query/my-subscriptions.ts
Normal file
21
src/graphql/query/my-subscriptions.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
import { gql } from '@urql/core'
|
||||
|
||||
export default gql`
|
||||
query MySubscriptionsQuery {
|
||||
loadMySubscriptions {
|
||||
topics {
|
||||
id
|
||||
title
|
||||
body
|
||||
slug
|
||||
}
|
||||
authors {
|
||||
id
|
||||
name
|
||||
slug
|
||||
userpic
|
||||
createdAt
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
|
@ -16,7 +16,6 @@ export type Scalars = {
|
|||
|
||||
export type AuthResult = {
|
||||
error?: Maybe<Scalars['String']>
|
||||
news?: Maybe<UserFollowings>
|
||||
token?: Maybe<Scalars['String']>
|
||||
user?: Maybe<User>
|
||||
}
|
||||
|
@ -302,6 +301,11 @@ export type MutationUpdateTopicArgs = {
|
|||
input: TopicInput
|
||||
}
|
||||
|
||||
export type MySubscriptionsQueryResult = {
|
||||
authors: Array<Maybe<Author>>
|
||||
topics: Array<Maybe<Topic>>
|
||||
}
|
||||
|
||||
export type Notification = {
|
||||
createdAt: Scalars['DateTime']
|
||||
data?: Maybe<Scalars['String']>
|
||||
|
@ -357,6 +361,7 @@ export type Query = {
|
|||
loadChats: Result
|
||||
loadDrafts: Array<Maybe<Shout>>
|
||||
loadMessagesBy: Result
|
||||
loadMySubscriptions?: Maybe<MySubscriptionsQueryResult>
|
||||
loadNotifications: NotificationsQueryResult
|
||||
loadReactionsBy: Array<Maybe<Reaction>>
|
||||
loadRecipients: Result
|
||||
|
@ -690,11 +695,3 @@ export type User = {
|
|||
username: Scalars['String']
|
||||
userpic?: Maybe<Scalars['String']>
|
||||
}
|
||||
|
||||
export type UserFollowings = {
|
||||
authors?: Maybe<Array<Maybe<Scalars['String']>>>
|
||||
communities?: Maybe<Array<Maybe<Scalars['String']>>>
|
||||
reactions?: Maybe<Array<Maybe<Scalars['Int']>>>
|
||||
topics?: Maybe<Array<Maybe<Scalars['String']>>>
|
||||
unread?: Maybe<Scalars['Int']>
|
||||
}
|
||||
|
|
|
@ -17,7 +17,8 @@ import type {
|
|||
ReactionBy,
|
||||
Shout,
|
||||
NotificationsQueryParams,
|
||||
NotificationsQueryResult
|
||||
NotificationsQueryResult,
|
||||
MySubscriptionsQueryResult
|
||||
} from '../graphql/types.gen'
|
||||
import { publicGraphQLClient } from '../graphql/publicGraphQLClient'
|
||||
import { getToken, privateGraphQLClient } from '../graphql/privateGraphQLClient'
|
||||
|
@ -58,6 +59,7 @@ import updateArticle from '../graphql/mutation/article-update'
|
|||
import deleteShout from '../graphql/mutation/article-delete'
|
||||
import notifications from '../graphql/query/notifications'
|
||||
import markNotificationAsRead from '../graphql/mutation/mark-notification-as-read'
|
||||
import mySubscriptions from '../graphql/query/my-subscriptions'
|
||||
|
||||
type ApiErrorCode =
|
||||
| 'unknown'
|
||||
|
@ -366,6 +368,12 @@ export const apiClient = {
|
|||
.toPromise()
|
||||
},
|
||||
|
||||
getMySubscriptions: async (): Promise<MySubscriptionsQueryResult> => {
|
||||
const resp = await privateGraphQLClient.query(mySubscriptions, {}).toPromise()
|
||||
// console.debug(resp.data)
|
||||
return resp.data.loadMySubscriptions
|
||||
},
|
||||
|
||||
// inbox
|
||||
getChats: async (options: QueryLoadChatsArgs): Promise<Chat[]> => {
|
||||
const resp = await privateGraphQLClient.query(myChats, options).toPromise()
|
||||
|
|
Loading…
Reference in New Issue
Block a user